force 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +96 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +107 -0
- data/Guardfile +8 -0
- data/LICENSE +22 -0
- data/README.md +421 -0
- data/Rakefile +10 -0
- data/coverage/assets/0.7.1/application.css +1110 -0
- data/coverage/assets/0.7.1/application.js +626 -0
- data/coverage/assets/0.7.1/fancybox/blank.gif +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_close.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_loading.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_nav_left.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_nav_right.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_e.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_n.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_ne.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_nw.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_s.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_se.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_sw.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_w.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_title_left.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_title_main.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_title_over.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_title_right.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancybox-x.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancybox-y.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancybox.png +0 -0
- data/coverage/assets/0.7.1/favicon_green.png +0 -0
- data/coverage/assets/0.7.1/favicon_red.png +0 -0
- data/coverage/assets/0.7.1/favicon_yellow.png +0 -0
- data/coverage/assets/0.7.1/loading.gif +0 -0
- data/coverage/assets/0.7.1/magnify.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coverage/index.html +19808 -0
- data/force.gemspec +27 -0
- data/lib/force.rb +74 -0
- data/lib/force/abstract_client.rb +9 -0
- data/lib/force/attachment.rb +21 -0
- data/lib/force/client.rb +3 -0
- data/lib/force/collection.rb +45 -0
- data/lib/force/concerns/api.rb +321 -0
- data/lib/force/concerns/authentication.rb +39 -0
- data/lib/force/concerns/base.rb +59 -0
- data/lib/force/concerns/caching.rb +24 -0
- data/lib/force/concerns/canvas.rb +10 -0
- data/lib/force/concerns/connection.rb +74 -0
- data/lib/force/concerns/picklists.rb +87 -0
- data/lib/force/concerns/streaming.rb +31 -0
- data/lib/force/concerns/verbs.rb +67 -0
- data/lib/force/config.rb +140 -0
- data/lib/force/data/client.rb +18 -0
- data/lib/force/mash.rb +66 -0
- data/lib/force/middleware.rb +27 -0
- data/lib/force/middleware/authentication.rb +73 -0
- data/lib/force/middleware/authentication/password.rb +17 -0
- data/lib/force/middleware/authentication/token.rb +15 -0
- data/lib/force/middleware/authorization.rb +15 -0
- data/lib/force/middleware/caching.rb +22 -0
- data/lib/force/middleware/gzip.rb +31 -0
- data/lib/force/middleware/instance_url.rb +14 -0
- data/lib/force/middleware/logger.rb +40 -0
- data/lib/force/middleware/mashify.rb +16 -0
- data/lib/force/middleware/multipart.rb +55 -0
- data/lib/force/middleware/raise_error.rb +25 -0
- data/lib/force/signed_request.rb +48 -0
- data/lib/force/sobject.rb +68 -0
- data/lib/force/tooling/client.rb +11 -0
- data/lib/force/upload_io.rb +20 -0
- data/lib/force/version.rb +3 -0
- data/spec/fixtures/auth_error_response.json +4 -0
- data/spec/fixtures/auth_success_response.json +7 -0
- data/spec/fixtures/blob.jpg +0 -0
- data/spec/fixtures/expired_session_response.json +6 -0
- data/spec/fixtures/reauth_success_response.json +7 -0
- data/spec/fixtures/refresh_error_response.json +4 -0
- data/spec/fixtures/refresh_success_response.json +7 -0
- data/spec/fixtures/services_data_success_response.json +12 -0
- data/spec/fixtures/sobject/create_success_response.json +5 -0
- data/spec/fixtures/sobject/delete_error_response.json +1 -0
- data/spec/fixtures/sobject/describe_sobjects_success_response.json +31 -0
- data/spec/fixtures/sobject/list_sobjects_success_response.json +31 -0
- data/spec/fixtures/sobject/org_query_response.json +11 -0
- data/spec/fixtures/sobject/query_aggregate_success_response.json +23 -0
- data/spec/fixtures/sobject/query_empty_response.json +5 -0
- data/spec/fixtures/sobject/query_error_response.json +6 -0
- data/spec/fixtures/sobject/query_paginated_first_page_response.json +14 -0
- data/spec/fixtures/sobject/query_paginated_last_page_response.json +13 -0
- data/spec/fixtures/sobject/query_success_response.json +38 -0
- data/spec/fixtures/sobject/recent_success_response.json +18 -0
- data/spec/fixtures/sobject/search_error_response.json +6 -0
- data/spec/fixtures/sobject/search_success_response.json +16 -0
- data/spec/fixtures/sobject/sobject_describe_error_response.json +6 -0
- data/spec/fixtures/sobject/sobject_describe_success_response.json +1429 -0
- data/spec/fixtures/sobject/sobject_find_error_response.json +6 -0
- data/spec/fixtures/sobject/sobject_find_success_response.json +29 -0
- data/spec/fixtures/sobject/upsert_created_success_response.json +5 -0
- data/spec/fixtures/sobject/upsert_error_response.json +6 -0
- data/spec/fixtures/sobject/upsert_multiple_error_response.json +4 -0
- data/spec/fixtures/sobject/upsert_updated_success_response.json +0 -0
- data/spec/fixtures/sobject/write_error_response.json +6 -0
- data/spec/integration/abstract_client_spec.rb +306 -0
- data/spec/integration/data/client_spec.rb +90 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/support/client_integration.rb +45 -0
- data/spec/support/concerns.rb +18 -0
- data/spec/support/event_machine.rb +14 -0
- data/spec/support/fixture_helpers.rb +45 -0
- data/spec/support/matchers.rb +11 -0
- data/spec/support/middleware.rb +76 -0
- data/spec/support/mock_cache.rb +13 -0
- data/spec/unit/abstract_client_spec.rb +11 -0
- data/spec/unit/attachment_spec.rb +15 -0
- data/spec/unit/collection_spec.rb +52 -0
- data/spec/unit/concerns/api_spec.rb +244 -0
- data/spec/unit/concerns/authentication_spec.rb +98 -0
- data/spec/unit/concerns/base_spec.rb +42 -0
- data/spec/unit/concerns/caching_spec.rb +29 -0
- data/spec/unit/concerns/canvas_spec.rb +30 -0
- data/spec/unit/concerns/connection_spec.rb +22 -0
- data/spec/unit/config_spec.rb +99 -0
- data/spec/unit/data/client_spec.rb +10 -0
- data/spec/unit/mash_spec.rb +36 -0
- data/spec/unit/middleware/authentication/password_spec.rb +31 -0
- data/spec/unit/middleware/authentication/token_spec.rb +24 -0
- data/spec/unit/middleware/authentication_spec.rb +67 -0
- data/spec/unit/middleware/authorization_spec.rb +11 -0
- data/spec/unit/middleware/gzip_spec.rb +66 -0
- data/spec/unit/middleware/instance_url_spec.rb +24 -0
- data/spec/unit/middleware/logger_spec.rb +19 -0
- data/spec/unit/middleware/mashify_spec.rb +11 -0
- data/spec/unit/middleware/raise_error_spec.rb +32 -0
- data/spec/unit/signed_request_spec.rb +24 -0
- data/spec/unit/sobject_spec.rb +86 -0
- data/spec/unit/tooling/client_spec.rb +7 -0
- data/tmp/rspec_guard_result +1 -0
- metadata +383 -0
data/force.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/force/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "force"
|
6
|
+
s.version = Force::VERSION
|
7
|
+
s.authors = ["Eric J. Holmes", "Mattt Thompson"]
|
8
|
+
s.email = ["eric@ejholmes.net", "mattt@heroku.com"]
|
9
|
+
s.description = "A lightweight ruby client for the Salesforce REST api."
|
10
|
+
s.summary = "A lightweight ruby client for the Salesforce REST api."
|
11
|
+
s.homepage = "https://github.com/heroku/force"
|
12
|
+
|
13
|
+
s.files = Dir["./**/*"].reject { |file| file =~ /\.\/(bin|example|log|pkg|script|spec|test|vendor)/ }
|
14
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
|
18
|
+
s.add_dependency 'faraday', '~> 0.8.4'
|
19
|
+
s.add_dependency 'faraday_middleware', '>= 0.8.8'
|
20
|
+
s.add_dependency 'json', ['>= 1.7.5', '< 1.9.0']
|
21
|
+
s.add_dependency 'hashie', ['>= 1.2.0', '< 2.1']
|
22
|
+
|
23
|
+
s.add_development_dependency 'rspec', '~> 2.14.0'
|
24
|
+
s.add_development_dependency 'webmock', '~> 1.13.0'
|
25
|
+
s.add_development_dependency 'simplecov', '~> 0.7.1'
|
26
|
+
s.add_development_dependency 'faye' unless RUBY_PLATFORM == 'java'
|
27
|
+
end
|
data/lib/force.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
require 'force/version'
|
6
|
+
require 'force/config'
|
7
|
+
|
8
|
+
module Force
|
9
|
+
autoload :AbstractClient, 'force/abstract_client'
|
10
|
+
autoload :SignedRequest, 'force/signed_request'
|
11
|
+
autoload :Collection, 'force/collection'
|
12
|
+
autoload :Middleware, 'force/middleware'
|
13
|
+
autoload :Attachment, 'force/attachment'
|
14
|
+
autoload :UploadIO, 'force/upload_io'
|
15
|
+
autoload :SObject, 'force/sobject'
|
16
|
+
autoload :Client, 'force/client'
|
17
|
+
autoload :Mash, 'force/mash'
|
18
|
+
|
19
|
+
module Concerns
|
20
|
+
autoload :Authentication, 'force/concerns/authentication'
|
21
|
+
autoload :Connection, 'force/concerns/connection'
|
22
|
+
autoload :Picklists, 'force/concerns/picklists'
|
23
|
+
autoload :Streaming, 'force/concerns/streaming'
|
24
|
+
autoload :Caching, 'force/concerns/caching'
|
25
|
+
autoload :Canvas, 'force/concerns/canvas'
|
26
|
+
autoload :Verbs, 'force/concerns/verbs'
|
27
|
+
autoload :Base, 'force/concerns/base'
|
28
|
+
autoload :API, 'force/concerns/api'
|
29
|
+
end
|
30
|
+
|
31
|
+
module Data
|
32
|
+
autoload :Client, 'force/data/client'
|
33
|
+
end
|
34
|
+
|
35
|
+
module Tooling
|
36
|
+
autoload :Client, 'force/tooling/client'
|
37
|
+
end
|
38
|
+
|
39
|
+
Error = Class.new(StandardError)
|
40
|
+
AuthenticationError = Class.new(Error)
|
41
|
+
UnauthorizedError = Class.new(Error)
|
42
|
+
|
43
|
+
class << self
|
44
|
+
# Alias for Force::Data::Client.new
|
45
|
+
#
|
46
|
+
# Shamelessly pulled from https://github.com/pengwynn/octokit/blob/master/lib/octokit.rb
|
47
|
+
def new(*args)
|
48
|
+
data(*args)
|
49
|
+
end
|
50
|
+
|
51
|
+
def data(*args)
|
52
|
+
Force::Data::Client.new(*args)
|
53
|
+
end
|
54
|
+
|
55
|
+
def tooling(*args)
|
56
|
+
Force::Tooling::Client.new(*args)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Helper for decoding signed requests.
|
60
|
+
def decode_signed_request(*args)
|
61
|
+
SignedRequest.decode(*args)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Add .tap method in Ruby 1.8
|
66
|
+
module CoreExtensions
|
67
|
+
def tap
|
68
|
+
yield self
|
69
|
+
self
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
Object.send :include, Force::CoreExtensions unless Object.respond_to? :tap
|
74
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Force
|
2
|
+
class Attachment < Force::SObject
|
3
|
+
# Public: Returns the body of the attachment.
|
4
|
+
#
|
5
|
+
# Examples
|
6
|
+
#
|
7
|
+
# attachment = client.query('select Id, Name, Body from Attachment').first
|
8
|
+
# File.open(attachment.Name, 'wb') { |f| f.write(attachment.Body) }
|
9
|
+
def Body
|
10
|
+
ensure_id && ensure_body
|
11
|
+
@client.get(super).body
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def ensure_body
|
17
|
+
return true if self.Body?
|
18
|
+
raise 'You need to query the Body for the record first.'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/force/client.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module Force
|
2
|
+
class Collection
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
# Given a hash and client, will create an Enumerator that will lazily
|
6
|
+
# request Salesforce for the next page of results.
|
7
|
+
def initialize(hash, client)
|
8
|
+
@client = client
|
9
|
+
@raw_page = hash
|
10
|
+
end
|
11
|
+
|
12
|
+
# Yield each value on each page.
|
13
|
+
def each
|
14
|
+
@raw_page['records'].each { |record| yield Force::Mash.build(record, @client) }
|
15
|
+
|
16
|
+
next_page.each { |record| yield record } if has_next_page?
|
17
|
+
end
|
18
|
+
|
19
|
+
# Return the size of the Collection without making any additional requests.
|
20
|
+
def size
|
21
|
+
@raw_page['totalSize']
|
22
|
+
end
|
23
|
+
alias_method :length, :size
|
24
|
+
|
25
|
+
# Return array of the elements on the current page
|
26
|
+
def current_page
|
27
|
+
first(@raw_page['records'].size)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return the current and all of the following pages.
|
31
|
+
def pages
|
32
|
+
[self] + (has_next_page? ? next_page.pages : [])
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns true if there is a pointer to the next page.
|
36
|
+
def has_next_page?
|
37
|
+
!@raw_page['nextRecordsUrl'].nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns the next page as a Force::Collection if it's available, nil otherwise.
|
41
|
+
def next_page
|
42
|
+
@next_page ||= @client.get(@raw_page['nextRecordsUrl']).body if has_next_page?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,321 @@
|
|
1
|
+
require 'force/concerns/verbs'
|
2
|
+
|
3
|
+
module Force
|
4
|
+
module Concerns
|
5
|
+
module API
|
6
|
+
extend Force::Concerns::Verbs
|
7
|
+
|
8
|
+
# Public: Helper methods for performing arbitrary actions against the API using
|
9
|
+
# various HTTP verbs.
|
10
|
+
#
|
11
|
+
# Examples
|
12
|
+
#
|
13
|
+
# # Perform a get request
|
14
|
+
# client.get '/services/data/v24.0/sobjects'
|
15
|
+
# client.api_get 'sobjects'
|
16
|
+
#
|
17
|
+
# # Perform a post request
|
18
|
+
# client.post '/services/data/v24.0/sobjects/Account', { ... }
|
19
|
+
# client.api_post 'sobjects/Account', { ... }
|
20
|
+
#
|
21
|
+
# # Perform a put request
|
22
|
+
# client.put '/services/data/v24.0/sobjects/Account/001D000000INjVe', { ... }
|
23
|
+
# client.api_put 'sobjects/Account/001D000000INjVe', { ... }
|
24
|
+
#
|
25
|
+
# # Perform a delete request
|
26
|
+
# client.delete '/services/data/v24.0/sobjects/Account/001D000000INjVe'
|
27
|
+
# client.api_delete 'sobjects/Account/001D000000INjVe'
|
28
|
+
#
|
29
|
+
# Returns the Faraday::Response.
|
30
|
+
define_verbs :get, :post, :put, :delete, :patch, :head
|
31
|
+
|
32
|
+
# Public: Get the names of all sobjects on the org.
|
33
|
+
#
|
34
|
+
# Examples
|
35
|
+
#
|
36
|
+
# # get the names of all sobjects on the org
|
37
|
+
# client.list_sobjects
|
38
|
+
# # => ['Account', 'Lead', ... ]
|
39
|
+
#
|
40
|
+
# Returns an Array of String names for each SObject.
|
41
|
+
def list_sobjects
|
42
|
+
describe.collect { |sobject| sobject['name'] }
|
43
|
+
end
|
44
|
+
|
45
|
+
# Public: Returns a detailed describe result for the specified sobject
|
46
|
+
#
|
47
|
+
# sobject - Stringish name of the sobject (default: nil).
|
48
|
+
#
|
49
|
+
# Examples
|
50
|
+
#
|
51
|
+
# # get the global describe for all sobjects
|
52
|
+
# client.describe
|
53
|
+
# # => { ... }
|
54
|
+
#
|
55
|
+
# # get the describe for the Account object
|
56
|
+
# client.describe('Account')
|
57
|
+
# # => { ... }
|
58
|
+
#
|
59
|
+
# Returns the Hash representation of the describe call.
|
60
|
+
def describe(sobject = nil)
|
61
|
+
if sobject
|
62
|
+
api_get("sobjects/#{sobject.to_s}/describe").body
|
63
|
+
else
|
64
|
+
api_get('sobjects').body['sobjects']
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Public: Returns a detailed description of the Page Layout for the
|
69
|
+
# specified sobject type, or URIs for layouts if the sobject has
|
70
|
+
# multiple Record Types.
|
71
|
+
#
|
72
|
+
# This resource was introduced in version 28.0.
|
73
|
+
#
|
74
|
+
# Examples:
|
75
|
+
# # get the layouts for the sobject
|
76
|
+
# client.describe_layouts('Account')
|
77
|
+
# # => { ... }
|
78
|
+
#
|
79
|
+
# # get the layout for the specified Id for the sobject
|
80
|
+
# client.describe_layouts('Account', '012E0000000RHEp')
|
81
|
+
# # => { ... }
|
82
|
+
#
|
83
|
+
# Returns the Hash representation of the describe_layouts result
|
84
|
+
def describe_layouts(sobject, layout_id = nil)
|
85
|
+
if layout_id
|
86
|
+
api_get("sobjects/#{sobject.to_s}/describe/layouts/#{layout_id}").body
|
87
|
+
else
|
88
|
+
api_get("sobjects/#{sobject.to_s}/describe/layouts").body
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Public: Get the current organization's Id.
|
93
|
+
#
|
94
|
+
# Examples
|
95
|
+
#
|
96
|
+
# client.org_id
|
97
|
+
# # => '00Dx0000000BV7z'
|
98
|
+
#
|
99
|
+
# Returns the String organization Id
|
100
|
+
def org_id
|
101
|
+
query('select id from Organization').first['Id']
|
102
|
+
end
|
103
|
+
|
104
|
+
# Public: Executs a SOQL query and returns the result.
|
105
|
+
#
|
106
|
+
# soql - A SOQL expression.
|
107
|
+
#
|
108
|
+
# Examples
|
109
|
+
#
|
110
|
+
# # Find the names of all Accounts
|
111
|
+
# client.query('select Name from Account').map(&:Name)
|
112
|
+
# # => ['Foo Bar Inc.', 'Whizbang Corp']
|
113
|
+
#
|
114
|
+
# Returns a Force::Collection if Force.configuration.mashify is true.
|
115
|
+
# Returns an Array of Hash for each record in the result if Force.configuration.mashify is false.
|
116
|
+
def query(soql)
|
117
|
+
response = api_get 'query', :q => soql
|
118
|
+
mashify? ? response.body : response.body['records']
|
119
|
+
end
|
120
|
+
|
121
|
+
# Public: Perform a SOSL search
|
122
|
+
#
|
123
|
+
# sosl - A SOSL expression.
|
124
|
+
#
|
125
|
+
# Examples
|
126
|
+
#
|
127
|
+
# # Find all occurrences of 'bar'
|
128
|
+
# client.search('FIND {bar}')
|
129
|
+
# # => #<Force::Collection >
|
130
|
+
#
|
131
|
+
# # Find accounts match the term 'genepoint' and return the Name field
|
132
|
+
# client.search('FIND {genepoint} RETURNING Account (Name)').map(&:Name)
|
133
|
+
# # => ['GenePoint']
|
134
|
+
#
|
135
|
+
# Returns a Force::Collection if Force.configuration.mashify is true.
|
136
|
+
# Returns an Array of Hash for each record in the result if Force.configuration.mashify is false.
|
137
|
+
def search(sosl)
|
138
|
+
api_get('search', :q => sosl).body
|
139
|
+
end
|
140
|
+
|
141
|
+
# Public: Insert a new record.
|
142
|
+
#
|
143
|
+
# sobject - String name of the sobject.
|
144
|
+
# attrs - Hash of attributes to set on the new record.
|
145
|
+
#
|
146
|
+
# Examples
|
147
|
+
#
|
148
|
+
# # Add a new account
|
149
|
+
# client.create('Account', Name: 'Foobar Inc.')
|
150
|
+
# # => '0016000000MRatd'
|
151
|
+
#
|
152
|
+
# Returns the String Id of the newly created sobject.
|
153
|
+
# Returns false if something bad happens.
|
154
|
+
def create(*args)
|
155
|
+
create!(*args)
|
156
|
+
rescue *exceptions
|
157
|
+
false
|
158
|
+
end
|
159
|
+
alias_method :insert, :create
|
160
|
+
|
161
|
+
# Public: Insert a new record.
|
162
|
+
#
|
163
|
+
# sobject - String name of the sobject.
|
164
|
+
# attrs - Hash of attributes to set on the new record.
|
165
|
+
#
|
166
|
+
# Examples
|
167
|
+
#
|
168
|
+
# # Add a new account
|
169
|
+
# client.create!('Account', Name: 'Foobar Inc.')
|
170
|
+
# # => '0016000000MRatd'
|
171
|
+
#
|
172
|
+
# Returns the String Id of the newly created sobject.
|
173
|
+
# Raises exceptions if an error is returned from Salesforce.
|
174
|
+
def create!(sobject, attrs)
|
175
|
+
api_post("sobjects/#{sobject}", attrs).body['id']
|
176
|
+
end
|
177
|
+
alias_method :insert!, :create!
|
178
|
+
|
179
|
+
# Public: Update a record.
|
180
|
+
#
|
181
|
+
# sobject - String name of the sobject.
|
182
|
+
# attrs - Hash of attributes to set on the record.
|
183
|
+
#
|
184
|
+
# Examples
|
185
|
+
#
|
186
|
+
# # Update the Account with Id '0016000000MRatd'
|
187
|
+
# client.update('Account', Id: '0016000000MRatd', Name: 'Whizbang Corp')
|
188
|
+
#
|
189
|
+
# Returns true if the sobject was successfully updated.
|
190
|
+
# Returns false if there was an error.
|
191
|
+
def update(*args)
|
192
|
+
update!(*args)
|
193
|
+
rescue *exceptions
|
194
|
+
false
|
195
|
+
end
|
196
|
+
|
197
|
+
# Public: Update a record.
|
198
|
+
#
|
199
|
+
# sobject - String name of the sobject.
|
200
|
+
# attrs - Hash of attributes to set on the record.
|
201
|
+
#
|
202
|
+
# Examples
|
203
|
+
#
|
204
|
+
# # Update the Account with Id '0016000000MRatd'
|
205
|
+
# client.update!('Account', Id: '0016000000MRatd', Name: 'Whizbang Corp')
|
206
|
+
#
|
207
|
+
# Returns true if the sobject was successfully updated.
|
208
|
+
# Raises an exception if an error is returned from Salesforce.
|
209
|
+
def update!(sobject, attrs)
|
210
|
+
id = attrs.delete(attrs.keys.find { |k| k.to_s.downcase == 'id' })
|
211
|
+
raise ArgumentError, 'Id field missing from attrs.' unless id
|
212
|
+
api_patch "sobjects/#{sobject}/#{id}", attrs
|
213
|
+
true
|
214
|
+
end
|
215
|
+
|
216
|
+
# Public: Update or create a record based on an external ID
|
217
|
+
#
|
218
|
+
# sobject - The name of the sobject to created.
|
219
|
+
# field - The name of the external Id field to match against.
|
220
|
+
# attrs - Hash of attributes for the record.
|
221
|
+
#
|
222
|
+
# Examples
|
223
|
+
#
|
224
|
+
# # Update the record with external ID of 12
|
225
|
+
# client.upsert('Account', 'External__c', External__c: 12, Name: 'Foobar')
|
226
|
+
#
|
227
|
+
# Returns true if the record was found and updated.
|
228
|
+
# Returns the Id of the newly created record if the record was created.
|
229
|
+
# Returns false if something bad happens.
|
230
|
+
def upsert(*args)
|
231
|
+
upsert!(*args)
|
232
|
+
rescue *exceptions
|
233
|
+
false
|
234
|
+
end
|
235
|
+
|
236
|
+
# Public: Update or create a record based on an external ID
|
237
|
+
#
|
238
|
+
# sobject - The name of the sobject to created.
|
239
|
+
# field - The name of the external Id field to match against.
|
240
|
+
# attrs - Hash of attributes for the record.
|
241
|
+
#
|
242
|
+
# Examples
|
243
|
+
#
|
244
|
+
# # Update the record with external ID of 12
|
245
|
+
# client.upsert!('Account', 'External__c', External__c: 12, Name: 'Foobar')
|
246
|
+
#
|
247
|
+
# Returns true if the record was found and updated.
|
248
|
+
# Returns the Id of the newly created record if the record was created.
|
249
|
+
# Raises an exception if an error is returned from Salesforce.
|
250
|
+
def upsert!(sobject, field, attrs)
|
251
|
+
external_id = attrs.delete(attrs.keys.find { |k| k.to_s.downcase == field.to_s.downcase })
|
252
|
+
response = api_patch "sobjects/#{sobject}/#{field.to_s}/#{external_id}", attrs
|
253
|
+
(response.body && response.body['id']) ? response.body['id'] : true
|
254
|
+
end
|
255
|
+
|
256
|
+
# Public: Delete a record.
|
257
|
+
#
|
258
|
+
# sobject - String name of the sobject.
|
259
|
+
# id - The Salesforce ID of the record.
|
260
|
+
#
|
261
|
+
# Examples
|
262
|
+
#
|
263
|
+
# # Delete the Account with Id '0016000000MRatd'
|
264
|
+
# client.destroy('Account', '0016000000MRatd')
|
265
|
+
#
|
266
|
+
# Returns true if the sobject was successfully deleted.
|
267
|
+
# Returns false if an error is returned from Salesforce.
|
268
|
+
def destroy(*args)
|
269
|
+
destroy!(*args)
|
270
|
+
rescue *exceptions
|
271
|
+
false
|
272
|
+
end
|
273
|
+
|
274
|
+
# Public: Delete a record.
|
275
|
+
#
|
276
|
+
# sobject - String name of the sobject.
|
277
|
+
# id - The Salesforce ID of the record.
|
278
|
+
#
|
279
|
+
# Examples
|
280
|
+
#
|
281
|
+
# # Delete the Account with Id '0016000000MRatd'
|
282
|
+
# client.destroy('Account', '0016000000MRatd')
|
283
|
+
#
|
284
|
+
# Returns true of the sobject was successfully deleted.
|
285
|
+
# Raises an exception if an error is returned from Salesforce.
|
286
|
+
def destroy!(sobject, id)
|
287
|
+
api_delete "sobjects/#{sobject}/#{id}"
|
288
|
+
true
|
289
|
+
end
|
290
|
+
|
291
|
+
# Public: Finds a single record and returns all fields.
|
292
|
+
#
|
293
|
+
# sobject - The String name of the sobject.
|
294
|
+
# id - The id of the record. If field is specified, id should be the id
|
295
|
+
# of the external field.
|
296
|
+
# field - External ID field to use (default: nil).
|
297
|
+
#
|
298
|
+
# Returns the Force::SObject sobject record.
|
299
|
+
def find(sobject, id, field=nil)
|
300
|
+
api_get(field ? "sobjects/#{sobject}/#{field}/#{id}" : "sobjects/#{sobject}/#{id}").body
|
301
|
+
end
|
302
|
+
|
303
|
+
private
|
304
|
+
|
305
|
+
# Internal: Returns a path to an api endpoint
|
306
|
+
#
|
307
|
+
# Examples
|
308
|
+
#
|
309
|
+
# api_path('sobjects')
|
310
|
+
# # => '/services/data/v24.0/sobjects'
|
311
|
+
def api_path(path)
|
312
|
+
"/services/data/v#{options[:api_version]}/#{path}"
|
313
|
+
end
|
314
|
+
|
315
|
+
# Internal: Errors that should be rescued from in non-bang methods
|
316
|
+
def exceptions
|
317
|
+
[Faraday::Error::ClientError]
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|