class SoqlData

Represents an API interaction via SOQL queries with the Salesforce database Usually this class is inherited by a class that represents a particular object, the only exception being the singleton methods in 'SoqlGlobalData'

Attributes

api_user[RW]

@return [String] User used to make api calls

Public Class Methods

create(*factory_parameters) click to toggle source

Create object using FactoryBot @param [Hash] factory_parameters Parameters to pass to FactoryBot

# File lib/leap_salesforce/soql_data/soql_data.rb, line 73
def self.create(*factory_parameters)
  FactoryBot.create(to_s.snakecase.to_sym, *factory_parameters)
end
descendants() click to toggle source

Returns descendants of the provided class SoqlData @return [Class] Classes that inherit from this class

# File lib/leap_salesforce/soql_data/soql_data.rb, line 256
def self.descendants
  ObjectSpace.each_object(Class).select { |class_name| class_name < self }
end
new(name = nil, http_parameters = {}) click to toggle source

Create a new SoqlData object. If override_parameters are empty then it's assumed creation of an object is being done

@example Create a new Contact step by step (Contact inherits from this class)

contact = Contact.new
contact.first_name = 'Bob'
contact.last_name = 'Smith'
contact.save! # API request made at this point

@example Create a Contact by specifying field names

contact = Contact.new first_name: 'Bob', last_name: 'Smith'
contact.save!

@example Create a contact using a factory with a trait of :email

contact_with_email = FactoryBot.create(:contact, :email)

@example Perform a get to the Salesforce limits api

SoqlData.new("Limits", method: :get, suburl: 'limits/')

@param [String, Hash] name Name describing object. Defaults to itself. If Hash is provided

with no 'http_parameters' then list will be fields to set on creating entity

@param [Hash] http_parameters Parameters used in making HTTP request. If creating a new object

leave this to empty. Otherwise Hash would look like method: :get, suburl: 'URL_AFTER_SOQL_HANDLER_BASE_URL'
Calls superclass method
# File lib/leap_salesforce/soql_data/soql_data.rb, line 47
def initialize(name = nil, http_parameters = {})
  super
  if @override_parameters && @override_parameters[:suburl]
    suburl_passed = @override_parameters[:suburl]
    @override_parameters[:suburl] = if suburl_passed.include?('sobjects')
                                      suburl_passed[suburl_passed.index('sobjects')..-1]
                                    else
                                      suburl_passed
                                    end
  end

  return unless http_parameters.empty?

  table_name = self.class.soql_object_name
  self.suburl = "sobjects/#{table_name}"
  optional_name = self.class.to_s == table_name ? '' : "(#{table_name})"
  self.test_name = "Factory for '#{self.class}'#{optional_name}" unless name
  return unless name.is_a? Hash

  name.dup.each do |field_name, field_value|
    send("#{field_name}=", field_value)
  end
end

Public Instance Methods

[](backend_name) click to toggle source

@return [String] Value at backend name

# File lib/leap_salesforce/soql_data/soql_data.rb, line 201
def [](backend_name)
  if @updated
    successful? unless backend_name.to_s == 'message' || backend_name.to_s == '$..message'
    @updated = false
    find # Retrieve data freshly after an update
  end
  value_from_path backend_name
rescue NoElementAtPath
  raise diagnose_error if error_message?

  find
  value_from_path backend_name
end
[]=(key, value) click to toggle source

Set a parameter request in the request body. Can be used to build a request over several steps (e.g Cucumber) Will be used with FactoryBot

@example

exchange['name'] = 'tester'
# Will set { name: tester } in the response, formatting as JSON or XML depending on REST / SOAP

@param [String, Symbol] key Name of request element to set @param [String] value Value to set request element to

# File lib/leap_salesforce/soql_data/soql_data.rb, line 194
def []=(key, value)
  value = value.salesforce_format if value.is_a? Time
  @override_parameters[:body] ||= {}
  @override_parameters[:body][key] = value
end
attach(filename) click to toggle source

Add the passed in file as an attachment to the object

# File lib/leap_salesforce/soql_data/soql_data.rb, line 174
def attach(filename)
  unless defined? Attachment
    raise LeapSalesforce::SetupError, 'Attachment not defined. ' \
    "Add to '.leap_salesforce.yml' to use this"
  end
  raise LeapSalesforce::Error, "Filename #{filename} does not exist" unless File.exist? filename

  FactoryBot.create(:attachment, ParentId: id, Name: File.split(filename).last,
                                 body: Base64.encode64(File.read(filename)))
end
delete(must_pass: false) click to toggle source

Delete current record @param [Boolean] must_pass Whether to raise exception if call is not successful @return [Exchange] Exchange object making delete

# File lib/leap_salesforce/soql_data/soql_data.rb, line 142
def delete(must_pass: false)
  sf_id = id
  self.class.delete(sf_id, must_pass: must_pass)
rescue NoElementAtPath
  LeapSalesforce.logger.warn "Tried to delete object that doesn't exist"
  self
end
delete_as_admin(must_pass: true) click to toggle source

Delete current record, switching to Admin before doing so @param [Boolean] must_pass Whether to raise exception if call is not successful @return [Exchange] Exchange object making delete

# File lib/leap_salesforce/soql_data/soql_data.rb, line 153
def delete_as_admin(must_pass: true)
  LeapSalesforce.api_user = LeapSalesforce::Users.where key: :admin
rescue LeapSalesforce::UserError
  raise LeapSalesforce::SetupError, 'Please set up a user with a key of :admin' \
  'to use "delete_as_admin"'
else
  delete must_pass: must_pass
end
diagnose_error() click to toggle source

@return [String, RestClient::Response] Error message if present

# File lib/leap_salesforce/soql_data/soql_data.rb, line 216
def diagnose_error
  return error_message if error_message?

  return response if @response # If response is made it would be helpful in diagnosing

  inspect # If no response, this may help
end
error_message() click to toggle source

@return [String] Error message if present. If not an error is raised

# File lib/leap_salesforce/soql_data/soql_data.rb, line 230
def error_message
  if error_message?
    value_from_path :message
  else
    message = "No error message received. Status code is #{status_code}. "
    message += 'Response is successful when it should not be. ' if status_code.to_s[0] == '2'
    message += 'Response is empty' if response.to_s.empty?
    raise LeapSalesforce::ResponseError, message

  end
end
error_message?() click to toggle source

@return [Boolean] Whether error message element is present

# File lib/leap_salesforce/soql_data/soql_data.rb, line 225
def error_message?
  error_message_element?
end
find() click to toggle source

Get details of itself by searching for it's id Store response within itself @return [Exchange] Exchange with details of data

# File lib/leap_salesforce/soql_data/soql_data.rb, line 117
def find
  @response = self.class.find(Id: id).response # Make get call and store result
  self
end
get() click to toggle source

@deprecated Get details of itself by searching for it's id Store response within itself @return [Exchange] Exchange with details of data

# File lib/leap_salesforce/soql_data/soql_data.rb, line 126
def get
  LeapSalesforce.logger.warn "Method 'get' called when it is deprecated" \
  " from #{caller_locations[0]}"
  find
end
id() click to toggle source

Extract the id or return the cached version of it @return [String] Id of Salesforce Object

# File lib/leap_salesforce/soql_data/soql_data.rb, line 102
def id
  @id ||= value_from_path '$..id,$..Id'
end
ids() click to toggle source

@return [Array] List of ids from response

# File lib/leap_salesforce/soql_data/soql_data.rb, line 169
def ids
  values_from_path('$..Id')
end
no_retry=(set) click to toggle source

@param [Boolean] set Whether to not retry for successful response (Used when you expect an error)

# File lib/leap_salesforce/soql_data/soql_data.rb, line 107
def no_retry=(set)
  return unless set

  # Set retry_count to 0 so if an invalid status code is returned a retry will not occur
  define_singleton_method('retry_count') { 0 }
end
open_on_ui() click to toggle source

Open Object on default browser

# File lib/leap_salesforce/soql_data/soql_data.rb, line 250
def open_on_ui
  Launchy.open("#{SoqlHandler.instance_url}/#{id}")
end
success_update(data) click to toggle source

Update current record with data provided expecting success @param [Hash] data Data to update exchange with

# File lib/leap_salesforce/soql_data/soql_data.rb, line 164
def success_update(data)
  update(**data, must_pass: true)
end
successful?() click to toggle source

@return [True, LeapSalesforce::ResponseError] Whether response is successful

# File lib/leap_salesforce/soql_data/soql_data.rb, line 243
def successful?
  raise LeapSalesforce::ResponseError, "Error with updating #{self} #{diagnose_error}" unless (200..299).cover? status_code

  true
end
unset=(element_to_unset, error: true) click to toggle source

Unsets the element so it's not set in the request at all (not just not setting it to empty) @todo: Allow mapping from ruby created field name to use as a parameter @param [String, Symbol] element_to_unset Element to remove from being sent @param [Boolean] error Whether to raise error if value to unset is not present

# File lib/leap_salesforce/soql_data/soql_data.rb, line 91
def unset=(element_to_unset, error: true)
  converted_element = element_to_unset.to_s
  unless @override_parameters[:body].key?(converted_element) && error
    raise LeapSalesforce::RequestError, "No backend name #{element_to_unset} in #{@override_parameters[:body]}\n" \
    "Valid values are #{@override_parameters[:body].keys}"
  end
  @override_parameters[:body].delete converted_element
end
update(data) click to toggle source

Update current record with data provided @param [Hash] data Data to update exchange with

# File lib/leap_salesforce/soql_data/soql_data.rb, line 134
def update(data)
  @updated = true
  self.class.update(id, data)
end