activeforce 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +15 -0
- data/Gemfile.lock +128 -0
- data/LICENSE.txt +20 -0
- data/README.md +112 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/activeforce.gemspec +151 -0
- data/app/models/salesforce/account.rb +4 -0
- data/app/models/salesforce/activity_history.rb +4 -0
- data/app/models/salesforce/approval.rb +4 -0
- data/app/models/salesforce/campaign.rb +4 -0
- data/app/models/salesforce/campaign_feed.rb +4 -0
- data/app/models/salesforce/campaign_member.rb +4 -0
- data/app/models/salesforce/case.rb +4 -0
- data/app/models/salesforce/case_comment.rb +4 -0
- data/app/models/salesforce/case_contact_role.rb +4 -0
- data/app/models/salesforce/case_feed.rb +4 -0
- data/app/models/salesforce/case_history.rb +4 -0
- data/app/models/salesforce/case_share.rb +4 -0
- data/app/models/salesforce/case_solution.rb +4 -0
- data/app/models/salesforce/case_status.rb +4 -0
- data/app/models/salesforce/case_team_member.rb +4 -0
- data/app/models/salesforce/community.rb +4 -0
- data/app/models/salesforce/contact.rb +4 -0
- data/app/models/salesforce/contact_feed.rb +4 -0
- data/app/models/salesforce/contact_history.rb +4 -0
- data/app/models/salesforce/contract.rb +4 -0
- data/app/models/salesforce/document.rb +4 -0
- data/app/models/salesforce/event.rb +4 -0
- data/app/models/salesforce/feed_item.rb +4 -0
- data/app/models/salesforce/group.rb +4 -0
- data/app/models/salesforce/group_member.rb +4 -0
- data/app/models/salesforce/idea.rb +4 -0
- data/app/models/salesforce/lead.rb +4 -0
- data/app/models/salesforce/lead_status.rb +4 -0
- data/app/models/salesforce/name.rb +4 -0
- data/app/models/salesforce/note.rb +4 -0
- data/app/models/salesforce/open_activity.rb +4 -0
- data/app/models/salesforce/opportunity.rb +4 -0
- data/app/models/salesforce/organization.rb +4 -0
- data/app/models/salesforce/partner.rb +4 -0
- data/app/models/salesforce/period.rb +4 -0
- data/app/models/salesforce/product2.rb +4 -0
- data/app/models/salesforce/product2_feed.rb +4 -0
- data/app/models/salesforce/profile.rb +4 -0
- data/app/models/salesforce/quote.rb +4 -0
- data/app/models/salesforce/solution.rb +4 -0
- data/app/models/salesforce/task.rb +4 -0
- data/app/models/salesforce/task_feed.rb +4 -0
- data/app/models/salesforce/task_priority.rb +4 -0
- data/app/models/salesforce/task_status.rb +4 -0
- data/app/models/salesforce/user.rb +4 -0
- data/app/models/salesforce/user_role.rb +4 -0
- data/app/models/salesforce/vote.rb +4 -0
- data/lib/activeforce.rb +29 -0
- data/lib/salesforce/attributes.rb +13 -0
- data/lib/salesforce/authentication.rb +25 -0
- data/lib/salesforce/base.rb +240 -0
- data/lib/salesforce/bulk/batch.rb +77 -0
- data/lib/salesforce/bulk/job.rb +103 -0
- data/lib/salesforce/bulk/operations.rb +25 -0
- data/lib/salesforce/bulk/update_job.rb +24 -0
- data/lib/salesforce/column.rb +98 -0
- data/lib/salesforce/columns.rb +60 -0
- data/lib/salesforce/config.rb +110 -0
- data/lib/salesforce/connection.rb +33 -0
- data/lib/salesforce/connection/async.rb +36 -0
- data/lib/salesforce/connection/conversion.rb +37 -0
- data/lib/salesforce/connection/http_methods.rb +72 -0
- data/lib/salesforce/connection/rest_api.rb +52 -0
- data/lib/salesforce/connection/soap_api.rb +74 -0
- data/lib/salesforce/engine.rb +6 -0
- data/lib/salesforce/errors.rb +33 -0
- data/test/salesforce/authentication_test.rb +52 -0
- data/test/salesforce/base_test.rb +440 -0
- data/test/salesforce/bulk/batch_test.rb +79 -0
- data/test/salesforce/bulk/update_job_test.rb +125 -0
- data/test/salesforce/column_test.rb +115 -0
- data/test/salesforce/config_test.rb +163 -0
- data/test/salesforce/connection/async_test.rb +138 -0
- data/test/salesforce/connection/http_methods_test.rb +242 -0
- data/test/salesforce/connection/rest_api_test.rb +61 -0
- data/test/salesforce/connection/soap_api_test.rb +148 -0
- data/test/salesforce/connection_test.rb +148 -0
- data/test/test_helper.rb +79 -0
- metadata +295 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'salesforce/connection/soap_api'
|
2
|
+
require 'salesforce/connection/rest_api'
|
3
|
+
require 'salesforce/connection/http_methods'
|
4
|
+
require 'salesforce/connection/conversion'
|
5
|
+
require 'salesforce/connection/async'
|
6
|
+
|
7
|
+
module Salesforce
|
8
|
+
module Connection
|
9
|
+
include SoapApi
|
10
|
+
include RestApi
|
11
|
+
include HttpMethods
|
12
|
+
include Conversion
|
13
|
+
include Async
|
14
|
+
|
15
|
+
def self.as_logged_in_user(&block)
|
16
|
+
count = 0
|
17
|
+
begin
|
18
|
+
Salesforce::Authentication.session_id
|
19
|
+
block.call
|
20
|
+
rescue RestClient::Request::Unauthorized, Savon::SOAP::Fault => e
|
21
|
+
if count < 1 && (e.message.downcase.include?("unauthorized") || e.message.downcase.include?("invalid_login"))
|
22
|
+
count += 1
|
23
|
+
Salesforce::Config.on_login_failure
|
24
|
+
Salesforce::Authentication.logout
|
25
|
+
retry
|
26
|
+
else
|
27
|
+
raise e
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Salesforce
|
2
|
+
module Connection
|
3
|
+
module Async
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def async_post(path, body, options = {})
|
8
|
+
url = async_api_url(path)
|
9
|
+
as_logged_in_user do
|
10
|
+
convert_body(RestClient.post(url, body, async_headers(options)), options)
|
11
|
+
end
|
12
|
+
rescue RestClient::ResourceNotFound, RestClient::BadRequest => e
|
13
|
+
convert_error(e, url, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def async_get(path, options = {})
|
17
|
+
url = async_api_url(path)
|
18
|
+
as_logged_in_user do
|
19
|
+
convert_body RestClient.get(url, async_headers(options)), options
|
20
|
+
end
|
21
|
+
rescue RestClient::ResourceNotFound, RestClient::BadRequest => e
|
22
|
+
convert_error(e, url, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def async_api_url(path)
|
26
|
+
::Salesforce::Config.async_url + "/" + path
|
27
|
+
end
|
28
|
+
|
29
|
+
def async_headers(options)
|
30
|
+
{ 'X-SFDC-Session' => Salesforce::Authentication.session_id }.merge(content_type_headers(options))
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Salesforce
|
2
|
+
module Connection
|
3
|
+
module Conversion
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
module ClassMethods
|
6
|
+
|
7
|
+
def convert_body(response, options)
|
8
|
+
convert(response.body, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def convert_error(error, url, options)
|
12
|
+
error_message = convert(error.http_body, options)
|
13
|
+
error_message = error_message.first if error_message.is_a?(Array)
|
14
|
+
error_message = error_message["Error"] if error_message.is_a?(Hash) && error_message["Error"]
|
15
|
+
raise InvalidRequest.new(error_message, url)
|
16
|
+
end
|
17
|
+
|
18
|
+
def convert(body, options)
|
19
|
+
if options[:format] == :json
|
20
|
+
ActiveSupport::JSON.decode(body)
|
21
|
+
elsif options[:format] == :xml
|
22
|
+
result = Hash.from_xml(body)
|
23
|
+
if result.is_a?(Hash) && result.keys.size == 1
|
24
|
+
result[result.keys.first].with_indifferent_access
|
25
|
+
else
|
26
|
+
result.with_indifferent_access
|
27
|
+
end
|
28
|
+
else
|
29
|
+
body
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end #ClassMethods
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Salesforce
|
2
|
+
module Connection
|
3
|
+
module HttpMethods
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
|
8
|
+
def headers(options = {})
|
9
|
+
{'Authorization' => "OAuth #{::Salesforce::Authentication.session_id}"}.merge(content_type_headers(options))
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(path, options = {})
|
13
|
+
http(:get, path, nil, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def patch(path, body, options = {})
|
17
|
+
http(:patch, path, body, options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def post(path, body, options = {})
|
21
|
+
http(:post, path, body, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete(path)
|
25
|
+
true if http(:delete, path, nil, :format => :xml)
|
26
|
+
end
|
27
|
+
|
28
|
+
def salesforce_url(path)
|
29
|
+
if path.include?("services/data")
|
30
|
+
::Salesforce::Config.server_host + path
|
31
|
+
else
|
32
|
+
::Salesforce::Config.server_url + "/" + path
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def http(action, path, body, options)
|
37
|
+
as_logged_in_user do
|
38
|
+
begin
|
39
|
+
response = if body
|
40
|
+
RestClient.send(action, salesforce_url(path), body, headers(options))
|
41
|
+
else
|
42
|
+
RestClient.send(action, salesforce_url(path), headers(options))
|
43
|
+
end
|
44
|
+
|
45
|
+
if response.body.present?
|
46
|
+
convert_body(response, options)
|
47
|
+
else
|
48
|
+
response
|
49
|
+
end
|
50
|
+
rescue RestClient::ResourceNotFound, RestClient::BadRequest => e
|
51
|
+
convert_error(e, salesforce_url(path), options)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def content_type_headers(options)
|
57
|
+
{}.tap do |hash|
|
58
|
+
hash[:content_type] = if options[:content_type]
|
59
|
+
options[:content_type]
|
60
|
+
elsif options[:format].to_s == 'json'
|
61
|
+
"application/json"
|
62
|
+
elsif options[:format].to_s == 'xml'
|
63
|
+
"application/xml"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end #ClassMethods
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Salesforce
|
2
|
+
module Connection
|
3
|
+
module RestApi
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
module ClassMethods
|
6
|
+
|
7
|
+
def supported_objects
|
8
|
+
get("sobjects.json", :format => :json)["sobjects"].map { |hash| hash["name"] }
|
9
|
+
end
|
10
|
+
|
11
|
+
def fields(object_name)
|
12
|
+
raise ObjectNotSupported.new(object_name) unless supported_objects.include?(object_name)
|
13
|
+
get("sobjects/#{object_name}/describe.json", :format => :json)["fields"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_object_by_id(object_name, object_id, fields)
|
17
|
+
get("sobjects/#{object_name}/#{object_id}.json?fields=#{URI.encode(fields)}", :format => :json)
|
18
|
+
end
|
19
|
+
|
20
|
+
def soql(query_string)
|
21
|
+
records = []
|
22
|
+
response = get "query.json?q=#{CGI.escape(query_string)}", :format => :json
|
23
|
+
records += response["records"].each { |r| r.delete("attributes")}
|
24
|
+
while(!response["done"])
|
25
|
+
response = get((response["nextRecordsUrl"] + '.json'), :format => :json)
|
26
|
+
records += response["records"].each { |r| r.delete("attributes")}
|
27
|
+
end
|
28
|
+
records
|
29
|
+
end
|
30
|
+
|
31
|
+
def update(object_name, object_id, fields)
|
32
|
+
response = patch("sobjects/#{object_name}/#{object_id}.json", fields.to_json, :format => :json)
|
33
|
+
response.code == 204
|
34
|
+
end
|
35
|
+
|
36
|
+
def create(object_name, fields)
|
37
|
+
result = post("sobjects/#{object_name}.json", fields.to_json, :format => :json)
|
38
|
+
if result["success"]
|
39
|
+
return result["id"]
|
40
|
+
else
|
41
|
+
raise RecordInvalid.new(object_name, result["errors"])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def destroy(object_name, object_id)
|
46
|
+
delete("sobjects/#{object_name}/#{object_id}")
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Salesforce
|
2
|
+
module Connection
|
3
|
+
module SoapApi
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
class Error < RuntimeError; end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
def login
|
11
|
+
options = {
|
12
|
+
:endpoint_url => Config.login_url,
|
13
|
+
:body => {
|
14
|
+
:username => Config.username,
|
15
|
+
:password => Config.password,
|
16
|
+
:order! => [ :username, :password ]
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
invoke_soap(:login, options)
|
21
|
+
end
|
22
|
+
|
23
|
+
def convert_lead(lead_converts)
|
24
|
+
options = { :body => { :leadConverts => lead_converts } }
|
25
|
+
|
26
|
+
as_logged_in_user do
|
27
|
+
invoke_soap(:convertLead, options)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def invoke_soap(method_name, options)
|
34
|
+
options[:namespace] ||= Config.soap_enterprise_namespace
|
35
|
+
options[:endpoint_url] ||= Config.soap_endpoint_url
|
36
|
+
|
37
|
+
result = soap_client(options).request :wsdl, method_name do |soap|
|
38
|
+
soap.body = options[:body]
|
39
|
+
|
40
|
+
unless method_name.to_sym == :login
|
41
|
+
soap.namespaces["xmlns:ns1"] = Config.soap_enterprise_namespace
|
42
|
+
soap.header = { "ns1:SessionHeader" => { "ns1:sessionId" => Config.session_id }}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
result.to_hash[:"#{method_name.to_s.underscore}_response"][:result].tap do |result|
|
47
|
+
unless result[:success] || method_name.to_sym == :login
|
48
|
+
raise_error(method_name, options, result[:errors])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def soap_client(options)
|
54
|
+
Savon::Client.new do
|
55
|
+
wsdl.namespace = options[:namespace]
|
56
|
+
wsdl.endpoint = options[:endpoint_url]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def raise_error(method_name, options, errors)
|
61
|
+
message = <<-MSG
|
62
|
+
\n
|
63
|
+
METHOD_NAME: #{method_name}
|
64
|
+
OPTIONS: #{options.inspect}
|
65
|
+
ERRORS: #{errors.inspect}
|
66
|
+
MSG
|
67
|
+
|
68
|
+
raise Error.new(message)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Salesforce
|
2
|
+
class InvalidRequest < StandardError
|
3
|
+
attr_accessor :error_code
|
4
|
+
|
5
|
+
def initialize(error_options, url)
|
6
|
+
@error_code = error_options['errorCode']
|
7
|
+
super("#{error_options["errorCode"]}: #{error_options["message"]} while accessing #{url}")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class ObjectNotSupported < StandardError
|
12
|
+
def initialize(object_name)
|
13
|
+
super("The #{object_name} is not supported in SalesForce")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class RecordInvalid < StandardError
|
18
|
+
def initialize(object_name, reason)
|
19
|
+
super("#{object_name} failed to be saved. #{reason}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class ColumnNotFound < StandardError
|
24
|
+
def initialize(name, table_name)
|
25
|
+
super("Column ''#{name}' not found for #{table_name}.")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
class InvalidCredentials < StandardError; end
|
31
|
+
class ObjectDestroyed < StandardError; end;
|
32
|
+
class UnrecognizedColumn < StandardError; end;
|
33
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Salesforce::AuthenticationTest < ActiveSupport::TestCase
|
4
|
+
def test_session_id__exists
|
5
|
+
Salesforce.configure do
|
6
|
+
username "username"
|
7
|
+
password "password"
|
8
|
+
end
|
9
|
+
Salesforce::Authentication.expects(:generate_new_session_id).never
|
10
|
+
Salesforce::Config.instance.session_id "existingsessionid"
|
11
|
+
assert_equal "existingsessionid", Salesforce::Authentication.session_id
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_session_id__doesnotexist
|
15
|
+
Salesforce.configure do
|
16
|
+
username "username"
|
17
|
+
password "password"
|
18
|
+
end
|
19
|
+
Salesforce::Authentication.expects(:generate_new_session_id).returns("new_session_id")
|
20
|
+
assert_equal "new_session_id", Salesforce::Authentication.session_id
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_session_id__credentials_missing
|
24
|
+
Salesforce::Authentication.expects(:generate_new_session_id).never
|
25
|
+
assert_raises Salesforce::InvalidCredentials do
|
26
|
+
Salesforce::Authentication.session_id
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_logout
|
31
|
+
Salesforce::Config.instance.session_id = "session_id"
|
32
|
+
Salesforce::Authentication.logout
|
33
|
+
assert_equal nil, Salesforce::Config.session_id
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_generate_new_session_id__calls_connection_login
|
37
|
+
result = {
|
38
|
+
:session_id => "session_id",
|
39
|
+
:server_url => "https://cs99-api.salesforce.com/services/Soap/c/22.0/00DQ00000001LRX",
|
40
|
+
:user_id => "user_id"
|
41
|
+
}
|
42
|
+
|
43
|
+
Salesforce.connection.expects(:login).returns(result)
|
44
|
+
|
45
|
+
assert_equal "session_id", Salesforce::Authentication.generate_new_session_id
|
46
|
+
assert_equal "https://cs99-api.salesforce.com/services/Soap/c/22.0/00DQ00000001LRX", Salesforce::Config.soap_endpoint_url
|
47
|
+
assert_equal "session_id", Salesforce::Config.session_id
|
48
|
+
assert_equal "cs99", Salesforce::Config.server_instance
|
49
|
+
assert_equal "user_id", Salesforce::Config.user_id
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,440 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Salesforce::OriginalTable < Salesforce::Base
|
4
|
+
end
|
5
|
+
|
6
|
+
class Salesforce::CustomTable < Salesforce::Base
|
7
|
+
self.custom_object = true
|
8
|
+
end
|
9
|
+
|
10
|
+
class Salesforce::BaseTest < ActiveSupport::TestCase
|
11
|
+
|
12
|
+
setup :clear_columns
|
13
|
+
|
14
|
+
def test_table_name
|
15
|
+
assert_equal "OriginalTable", Salesforce::OriginalTable.table_name
|
16
|
+
assert_equal "CustomTable__c", Salesforce::CustomTable.table_name
|
17
|
+
Salesforce::CustomTable.custom_table_name = "this_is_your_name"
|
18
|
+
assert_equal "this_is_your_name", Salesforce::CustomTable.table_name
|
19
|
+
ensure
|
20
|
+
Salesforce::CustomTable.custom_table_name = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_columns
|
24
|
+
setup_columns_for_custom_table
|
25
|
+
obj = Salesforce::CustomTable.new(:name => "tushar", :account => "account")
|
26
|
+
assert_equal "tushar", obj.name
|
27
|
+
assert_equal "account", obj.account
|
28
|
+
|
29
|
+
obj = Salesforce::CustomTable.new
|
30
|
+
obj.name = "tushar"
|
31
|
+
assert_equal "tushar", obj.name
|
32
|
+
|
33
|
+
obj = Salesforce::CustomTable.new
|
34
|
+
obj.Name__c = "tushar"
|
35
|
+
obj.Car__c = "Ferrari"
|
36
|
+
obj.Id = "newid"
|
37
|
+
assert_equal "tushar", obj.name
|
38
|
+
assert_equal "Ferrari", obj.car
|
39
|
+
assert_equal "newid", obj.id
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_column_attr_createable_columns__new_record
|
43
|
+
setup_columns_for_custom_table
|
44
|
+
obj = Salesforce::CustomTable.new
|
45
|
+
assert_nothing_raised do
|
46
|
+
obj.account = "account"
|
47
|
+
obj.name = "foo"
|
48
|
+
obj.attributes = { :account => 'account2', :name => 'foo'}
|
49
|
+
assert_equal 'account2', obj.account
|
50
|
+
assert_equal 'foo', obj.name
|
51
|
+
end
|
52
|
+
|
53
|
+
assert_raises ArgumentError do
|
54
|
+
obj.car = "car"
|
55
|
+
end
|
56
|
+
|
57
|
+
assert_raises ArgumentError do
|
58
|
+
obj.attributes = { :car => 'car2'}
|
59
|
+
end
|
60
|
+
|
61
|
+
assert_raises NoMethodError do
|
62
|
+
obj.id = "id"
|
63
|
+
end
|
64
|
+
|
65
|
+
assert_raises NoMethodError do
|
66
|
+
obj.attributes = { :id => 'id2'}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_attributes__creatable_and_updateable
|
71
|
+
setup_columns_for_custom_table
|
72
|
+
obj = Salesforce::CustomTable.new("Id"=> "id", "Account__c" => "account", "Car__c" => 'car', "Name__c" => 'name')
|
73
|
+
assert_equal({"name"=>"name", "account"=>"account", "id"=>"id", "car"=>"car"}, obj.attributes)
|
74
|
+
assert_equal({"Account__c"=>"account", "Name__c"=>"name"}, obj.createable_attributes)
|
75
|
+
assert_equal({"Car__c"=>"car", "Name__c"=>"name"}, obj.updateable_attributes)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_column_attr_updateable_columns__existing_record
|
79
|
+
setup_columns_for_custom_table
|
80
|
+
obj = Salesforce::CustomTable.new("Id" => "id")
|
81
|
+
|
82
|
+
assert_nothing_raised do
|
83
|
+
obj.name = "foo"
|
84
|
+
obj.car = "car"
|
85
|
+
obj.attributes = { :name => 'foo2', :car => 'car2' }
|
86
|
+
assert_equal 'foo2', obj.name
|
87
|
+
assert_equal 'car2', obj.car
|
88
|
+
end
|
89
|
+
|
90
|
+
assert_raises ArgumentError do
|
91
|
+
obj.account = "account"
|
92
|
+
end
|
93
|
+
|
94
|
+
assert_raises ArgumentError do
|
95
|
+
obj.attributes = { :account => 'account2' }
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
assert_raises NoMethodError do
|
101
|
+
obj.id = "id"
|
102
|
+
end
|
103
|
+
|
104
|
+
assert_raises NoMethodError do
|
105
|
+
obj.attributes = { :id => 'id' }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_save__create
|
110
|
+
setup_columns_for_custom_table
|
111
|
+
Salesforce.connection.expects(:create).with('CustomTable__c', { 'Account__c' => 'account', "Name__c" => "name"}).returns("newid")
|
112
|
+
obj = Salesforce::CustomTable.new(:account => 'account', :name => 'name')
|
113
|
+
obj.save!
|
114
|
+
assert_equal 'newid', obj.id
|
115
|
+
assert_equal false, obj.new_record?
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_save__create_fails
|
119
|
+
setup_columns_for_custom_table
|
120
|
+
error = Salesforce::RecordInvalid.new('CustomTable__c', 'msg')
|
121
|
+
Salesforce.connection.expects(:create).raises(error)
|
122
|
+
obj = Salesforce::CustomTable.new(:account => 'account', :name => 'name')
|
123
|
+
assert_raises Salesforce::RecordInvalid do
|
124
|
+
obj.save!
|
125
|
+
end
|
126
|
+
assert obj.new_record?
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_save__update
|
130
|
+
setup_columns_for_custom_table
|
131
|
+
Salesforce.connection.expects(:update).with('CustomTable__c', 'oldid', {'Name__c' => 'newname', 'Car__c' => 'mycar'})
|
132
|
+
obj = Salesforce::CustomTable.new(:Account__c => 'account', :name => 'newname', :Id => "oldid", :Car__c => 'mycar')
|
133
|
+
assert_equal false, obj.new_record?
|
134
|
+
obj.save!
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_update__wrapped_by_with_invalid_column_handling
|
138
|
+
Salesforce::OriginalTable.stubs(:columns)
|
139
|
+
Salesforce::OriginalTable.expects(:with_invalid_column_handling).returns(:update_result)
|
140
|
+
assert_equal :update_result, Salesforce::OriginalTable.new.update
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_save__update_fails
|
144
|
+
setup_columns_for_custom_table
|
145
|
+
error = Salesforce::RecordInvalid.new('CustomTable__c', 'msg')
|
146
|
+
Salesforce.connection.expects(:update).raises(error)
|
147
|
+
obj = Salesforce::CustomTable.new(:Account__c => 'account', :name => 'newname', :Id => "oldid", :Car__c => 'mycar')
|
148
|
+
assert_raises Salesforce::RecordInvalid do
|
149
|
+
obj.save!
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_destroy
|
154
|
+
setup_columns_for_custom_table
|
155
|
+
Salesforce.connection.expects(:destroy).with('CustomTable__c', 'oldid')
|
156
|
+
obj = Salesforce::CustomTable.new(:Account__c => 'account', :name => 'newname', :Id => "oldid")
|
157
|
+
obj.destroy
|
158
|
+
assert obj.destroyed?
|
159
|
+
assert_raises Salesforce::ObjectDestroyed do
|
160
|
+
obj.save!
|
161
|
+
end
|
162
|
+
|
163
|
+
assert_raises Salesforce::ObjectDestroyed do
|
164
|
+
obj.destroy
|
165
|
+
end
|
166
|
+
|
167
|
+
assert_raises Salesforce::ObjectDestroyed do
|
168
|
+
obj.create
|
169
|
+
end
|
170
|
+
|
171
|
+
assert_raises Salesforce::ObjectDestroyed do
|
172
|
+
obj.update
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_destroy__new_record
|
177
|
+
setup_columns_for_custom_table
|
178
|
+
Salesforce.connection.expects(:destroy).never
|
179
|
+
obj = Salesforce::CustomTable.new(:Account__c => 'account', :name => 'newname')
|
180
|
+
assert obj.new_record?
|
181
|
+
obj.destroy
|
182
|
+
assert obj.destroyed?
|
183
|
+
assert_raises Salesforce::ObjectDestroyed do
|
184
|
+
obj.save!
|
185
|
+
end
|
186
|
+
|
187
|
+
assert_raises Salesforce::ObjectDestroyed do
|
188
|
+
obj.destroy
|
189
|
+
end
|
190
|
+
|
191
|
+
assert_raises Salesforce::ObjectDestroyed do
|
192
|
+
obj.create
|
193
|
+
end
|
194
|
+
|
195
|
+
assert_raises Salesforce::ObjectDestroyed do
|
196
|
+
obj.update
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
def test_find
|
202
|
+
Salesforce::OriginalTable.expects(:find_by_id).with("id")
|
203
|
+
Salesforce::OriginalTable.find("id")
|
204
|
+
|
205
|
+
Salesforce::OriginalTable.expects(:find_all)
|
206
|
+
Salesforce::OriginalTable.find(:all)
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_find_by_id
|
210
|
+
setup_columns_for_original_table
|
211
|
+
Salesforce.connection.expects(:find_object_by_id).with("OriginalTable", "id", "Col1,Col2__c").returns({ "Col1" => 'col11', "Col2__c" => 'col21'})
|
212
|
+
result = Salesforce::OriginalTable.find_by_id("id")
|
213
|
+
assert_equal "col11", result.col1
|
214
|
+
assert_equal "col21", result.col2
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_find_by_id__wrapped_by_with_invalid_column_handling
|
218
|
+
Salesforce::OriginalTable.expects(:with_invalid_column_handling).returns(:find_by_id_result)
|
219
|
+
|
220
|
+
assert_equal :find_by_id_result, Salesforce::OriginalTable.find_by_id(anything)
|
221
|
+
end
|
222
|
+
|
223
|
+
def test_find_by_id__columns_not_set
|
224
|
+
columns_hash = [{"name" => "Col1", "type" => "id"}, { "name" => "Col2__c", "type" => "string" } ]
|
225
|
+
columns = columns_hash.map { |hash| Salesforce::Column.new(hash) }
|
226
|
+
Salesforce.connection.expects(:fields).with("CustomTable__c").returns(columns_hash)
|
227
|
+
Salesforce.connection.expects(:find_object_by_id).with("CustomTable__c", "id", "Col1,Col2__c").returns("Col1" => 'col11', "Col2__c" => 'col21')
|
228
|
+
result = Salesforce::CustomTable.find_by_id("id")
|
229
|
+
assert_equal "col11", result.col1
|
230
|
+
assert_equal "col21", result.col2
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_find_all
|
234
|
+
setup_columns_for_original_table
|
235
|
+
Salesforce.connection.expects(:soql).with("SELECT Col1,Col2__c FROM OriginalTable").returns([ { "Col1" => 'col11', "Col2__c" => 'col21'}, { "Col1" => 'col21', "Col2__c" => 'col22'}])
|
236
|
+
results = Salesforce::OriginalTable.find(:all)
|
237
|
+
assert_equal 2, results.size
|
238
|
+
assert_equal "col11", results.first.col1
|
239
|
+
assert_equal "col21", results.first.col2
|
240
|
+
assert_equal "col21", results.last.col1
|
241
|
+
assert_equal "col22", results.last.col2
|
242
|
+
end
|
243
|
+
def test_find_all__wrapped_by_with_invalid_column_handling
|
244
|
+
Salesforce::OriginalTable.expects(:with_invalid_column_handling).returns(:find_all_result)
|
245
|
+
|
246
|
+
assert_equal :find_all_result, Salesforce::OriginalTable.find_all
|
247
|
+
end
|
248
|
+
|
249
|
+
def test_find_all__with_select
|
250
|
+
setup_columns_for_original_table
|
251
|
+
Salesforce.connection.expects(:soql).with("SELECT Col2__c FROM OriginalTable").returns([ { "Col2__c" => 'col21'}, { "Col2__c" => 'col22'}])
|
252
|
+
results = Salesforce::OriginalTable.find(:all, :select => :col2)
|
253
|
+
assert_equal 2, results.size
|
254
|
+
assert_equal "col21", results.first.col2
|
255
|
+
assert_equal "col22", results.last.col2
|
256
|
+
end
|
257
|
+
|
258
|
+
def test_find_all__with_conditions
|
259
|
+
setup_columns_for_original_table
|
260
|
+
Salesforce.connection.expects(:soql).with("SELECT Col1,Col2__c FROM OriginalTable WHERE Col2__c >= 2011-11-11").returns([ { "Col2__c" => 'col21'}, { "Col2__c" => 'col22'}])
|
261
|
+
results = Salesforce::OriginalTable.find(:all, :conditions => ":col2 >= :date", :date => Date.parse("11/11/2011"))
|
262
|
+
assert_equal 2, results.size
|
263
|
+
assert_equal "col21", results.first.col2
|
264
|
+
assert_equal "col22", results.last.col2
|
265
|
+
end
|
266
|
+
|
267
|
+
def test_query_string
|
268
|
+
Salesforce.connection.expects(:fields).with("OriginalTable").returns([
|
269
|
+
{ "name" => "Col1", "type" => "id" },
|
270
|
+
{"name" => "Col2__c", "type" => "string"},
|
271
|
+
{"name" => "Col3__c", "type" => "datetime"},
|
272
|
+
{"name" => "ZCol4__c", "type" => "date"},
|
273
|
+
{"name" => "ACol5__c", "type" => "boolean"}
|
274
|
+
])
|
275
|
+
|
276
|
+
Salesforce::OriginalTable.columns
|
277
|
+
|
278
|
+
assert_equal "SELECT ACol5__c,Col1,Col2__c,Col3__c,ZCol4__c FROM OriginalTable", Salesforce::OriginalTable.query_string({})
|
279
|
+
assert_equal "SELECT ACol5__c FROM OriginalTable", Salesforce::OriginalTable.query_string({:select => :a_col5})
|
280
|
+
assert_equal "SELECT ZCol4__c,Col2__c FROM OriginalTable", Salesforce::OriginalTable.query_string({:select => [ :z_col4, :col2 ]})
|
281
|
+
|
282
|
+
assert_equal "SELECT ACol5__c FROM OriginalTable WHERE Col1 > Col2__c", Salesforce::OriginalTable.query_string(:select => :a_col5, :conditions => ":col1 > :col2")
|
283
|
+
assert_equal "SELECT ACol5__c FROM OriginalTable WHERE Col1 > Col2__c", Salesforce::OriginalTable.query_string(:select => :a_col5, :conditions => ":col1 > :col2")
|
284
|
+
assert_equal "SELECT ACol5__c FROM OriginalTable WHERE Col1 > 2011-08-01", Salesforce::OriginalTable.query_string(:select => :a_col5, :conditions => ":col1 > :date",
|
285
|
+
:date => Date.parse('08/01/2011') )
|
286
|
+
assert_equal "SELECT ACol5__c FROM OriginalTable WHERE Col1 > 2011-08-01 AND ACol5__c = 2011-08-01T09:30:00-07:00",
|
287
|
+
Salesforce::OriginalTable.query_string(:select => :a_col5,
|
288
|
+
:conditions => ":col1 > :date AND :a_col5 = :time", :date => Date.parse('08/01/2011'), :time => Time.zone.parse("08/01/2011 09:30 AM"))
|
289
|
+
|
290
|
+
assert_equal "SELECT ACol5__c FROM OriginalTable WHERE Col1 = TRUE AND Col2__c = FALSE AND Col3__c = NULL",
|
291
|
+
Salesforce::OriginalTable.query_string(:select => :a_col5,
|
292
|
+
:conditions => ":col1 = :true AND :col2 = :false AND :col3 = :nil", :true => true, :false => false, :nil => nil)
|
293
|
+
|
294
|
+
assert_equal "SELECT ACol5__c FROM OriginalTable WHERE Col1 = 'string'",
|
295
|
+
Salesforce::OriginalTable.query_string(:select => :a_col5, :conditions => ":col1 = :string", :string => 'string' )
|
296
|
+
|
297
|
+
assert_equal "SELECT ACol5__c FROM OriginalTable WHERE Col1 = 'string' ORDER BY Col1",
|
298
|
+
Salesforce::OriginalTable.query_string(:select => :a_col5, :conditions => ":col1 = :string", :string => 'string', :order => :col1)
|
299
|
+
|
300
|
+
assert_equal "SELECT ACol5__c FROM OriginalTable WHERE Col1 = 'string' ORDER BY Col1 ASC, Col3__c DESC",
|
301
|
+
Salesforce::OriginalTable.query_string(:select => :a_col5, :conditions => ":col1 = :string",
|
302
|
+
:string => 'string' , :order => ":col1 ASC, :col3 DESC")
|
303
|
+
|
304
|
+
assert_equal "SELECT ACol5__c FROM OriginalTable WHERE Col1 = 'string' GROUP BY Col2__c HAVING Col3__c > 2009-08-01 ORDER BY Col1 ASC, Col3__c DESC",
|
305
|
+
Salesforce::OriginalTable.query_string(:select => :a_col5, :conditions => ":col1 = :string", :group_by => :col2, :having => ":col3 > :date",
|
306
|
+
:string => 'string', :date => Date.parse('08/01/2009'), :order => ":col1 ASC, :col3 DESC")
|
307
|
+
|
308
|
+
|
309
|
+
|
310
|
+
assert_raises Salesforce::ColumnNotFound do
|
311
|
+
Salesforce::OriginalTable.query_string({:select => [ :col4 ]})
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def test_find_all__columns_not_set
|
316
|
+
columns_hash = [{"name" => "Col1", "type" => "id"}, { "name" => "Col2__c", "type" => "string" } ]
|
317
|
+
columns = columns_hash.map { |hash| Salesforce::Column.new(hash) }
|
318
|
+
Salesforce.connection.expects(:fields).with("CustomTable__c").returns(columns_hash)
|
319
|
+
Salesforce.connection.expects(:soql).with("SELECT Col1,Col2__c FROM CustomTable__c").returns([ { "Col1" => 'col11', "Col2__c" => 'col21'}, { "Col1" => 'col21', "Col2__c" => 'col22'} ])
|
320
|
+
results = Salesforce::CustomTable.find(:all)
|
321
|
+
assert_equal 2, results.size
|
322
|
+
assert_equal "col11", results.first.col1
|
323
|
+
assert_equal "col21", results.first.col2
|
324
|
+
assert_equal "col21", results.last.col1
|
325
|
+
assert_equal "col22", results.last.col2
|
326
|
+
end
|
327
|
+
|
328
|
+
def test_dynamic_finders
|
329
|
+
setup_columns_for_original_table
|
330
|
+
|
331
|
+
Salesforce::OriginalTable.expects(:find_by_column).with do |col, value|
|
332
|
+
col.original_name == "Col1" && value == "col1value"
|
333
|
+
end.returns(:find_by_col1_result)
|
334
|
+
|
335
|
+
assert_equal :find_by_col1_result, Salesforce::OriginalTable.find_by_col1("col1value")
|
336
|
+
|
337
|
+
Salesforce::OriginalTable.expects(:find_by_column).with do |col, value|
|
338
|
+
col.original_name == "Col2__c" && value == "col2value"
|
339
|
+
end.returns(:find_by_col2_result)
|
340
|
+
|
341
|
+
assert_equal :find_by_col2_result, Salesforce::OriginalTable.find_by_col2("col2value")
|
342
|
+
|
343
|
+
Salesforce::OriginalTable.expects(:find_by_column).never
|
344
|
+
|
345
|
+
assert_raises NoMethodError do
|
346
|
+
Salesforce::OriginalTable.find_by_col3("col1value")
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def test_find_by_column
|
351
|
+
setup_columns_for_original_table
|
352
|
+
Salesforce.connection.expects(:soql).with("SELECT Col1,Col2__c FROM OriginalTable WHERE Col2__c='value'").returns([ { "Col1" => 'col11', "Col2__c" => 'col21'}, { "Col1" => 'col21', "Col2__c" => 'col22'} ])
|
353
|
+
results = Salesforce::OriginalTable.find_by_column(Salesforce::OriginalTable.columns.all.last, "value")
|
354
|
+
assert_equal 2, results.size
|
355
|
+
assert_equal "col11", results.first.col1
|
356
|
+
assert_equal "col21", results.first.col2
|
357
|
+
assert_equal "col21", results.last.col1
|
358
|
+
assert_equal "col22", results.last.col2
|
359
|
+
end
|
360
|
+
|
361
|
+
def test_select_values
|
362
|
+
setup_columns_for_original_table
|
363
|
+
Salesforce::OriginalTable.expects(:query_string).with(:select => [ :col1, :col2 ], :other => :options).returns("sql_query")
|
364
|
+
Salesforce.connection.expects(:soql).with("sql_query").returns([ { "Col1" => '123456789012345678', "Col2__c" => 'col21'}, { "Col1" => '123456789012345678', "Col2__c" => 'col22'} ])
|
365
|
+
results = Salesforce::OriginalTable.select_values(:select => [ :col1, :col2 ], :other => :options)
|
366
|
+
assert_equal 2, results.size
|
367
|
+
assert_equal({ :col1 => '123456789012345', :col2 => 'col21'}, results.first)
|
368
|
+
assert_equal({ :col1 => '123456789012345', :col2 => 'col22'}, results.last)
|
369
|
+
end
|
370
|
+
|
371
|
+
def test_with_invalid_column_handling__succeeds_the_first_time
|
372
|
+
value = Salesforce::OriginalTable.with_invalid_column_handling do
|
373
|
+
:foo
|
374
|
+
end
|
375
|
+
|
376
|
+
assert_equal :foo, value
|
377
|
+
end
|
378
|
+
|
379
|
+
def test_with_invalid_column_handling__throws_invalid_fields_error__more_than_once
|
380
|
+
assert_raises Salesforce::InvalidRequest do
|
381
|
+
Salesforce::OriginalTable.with_invalid_column_handling do
|
382
|
+
raise Salesforce::InvalidRequest.new({ 'errorCode' => 'INVALID_FIELD'}, '/foo')
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
def test_with_invalid_column_handling__throws_invalid_fields_error__more_than_once
|
388
|
+
error = RuntimeError.new
|
389
|
+
Salesforce::OriginalTable.expects(:clear_cached_columns!).never
|
390
|
+
|
391
|
+
assert_raises error.class do
|
392
|
+
Salesforce::OriginalTable.with_invalid_column_handling do
|
393
|
+
raise error
|
394
|
+
end
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
def test_with_invalid_column_handling__throws_invalid_fields_error__once__then_recovers
|
399
|
+
count = 0
|
400
|
+
|
401
|
+
Salesforce::OriginalTable.expects(:clear_cached_columns!)
|
402
|
+
value = Salesforce::OriginalTable.with_invalid_column_handling do
|
403
|
+
if count < 1
|
404
|
+
count += 1
|
405
|
+
raise Salesforce::InvalidRequest.new({ 'errorCode' => 'INVALID_FIELD'}, '/foo')
|
406
|
+
end
|
407
|
+
:bar
|
408
|
+
end
|
409
|
+
|
410
|
+
assert_equal :bar, value
|
411
|
+
end
|
412
|
+
|
413
|
+
private
|
414
|
+
|
415
|
+
def clear_columns
|
416
|
+
Salesforce::CustomTable.cached_columns = nil
|
417
|
+
Salesforce::OriginalTable.cached_columns = nil
|
418
|
+
end
|
419
|
+
|
420
|
+
def setup_columns_for_original_table
|
421
|
+
Salesforce.connection.expects(:fields).with("OriginalTable").returns([ { "name" => "Col1", "type" => "id" }, {"name" => "Col2__c", "type" => "id"} ])
|
422
|
+
Salesforce::OriginalTable.columns
|
423
|
+
end
|
424
|
+
|
425
|
+
def setup_columns_for_custom_table
|
426
|
+
columns_hash = [
|
427
|
+
{ "name" => "Id", "type" => "id", "createable" => false, "updateable" => false},
|
428
|
+
{ "name" => "Account__c", "type" => "reference", "createable" => true, "updateable" => false, "custom" => true },
|
429
|
+
{ "name" => "Car__c", "type" => "reference", "createable" => false, "updateable" => true, "custom" => true},
|
430
|
+
{ "name" => "Name__c", "type" => "string", "createable" => true, "updateable" => true, "custom" => true}
|
431
|
+
]
|
432
|
+
|
433
|
+
Salesforce.connection.expects(:fields).with("CustomTable__c").returns(columns_hash).twice
|
434
|
+
columns = Salesforce::Columns.new("CustomTable__c")
|
435
|
+
assert_equal columns, Salesforce::CustomTable.columns
|
436
|
+
end
|
437
|
+
|
438
|
+
|
439
|
+
end
|
440
|
+
|