activesalesforce 0.0.4 → 0.0.5
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/lib/rforce.rb +53 -41
- data/lib/salesforce_active_record.rb +1 -0
- data/lib/salesforce_connection_adapter.rb +21 -16
- metadata +2 -2
data/lib/rforce.rb
CHANGED
@@ -54,7 +54,7 @@ require_gem 'builder'
|
|
54
54
|
# binding.create 'sObject {"xsi:type" => "Opportunity"}' => opportunity
|
55
55
|
#
|
56
56
|
module RForce
|
57
|
-
|
57
|
+
|
58
58
|
#Allows indexing hashes like method calls: hash.key
|
59
59
|
#to supplement the traditional way of indexing: hash[key]
|
60
60
|
module FlashHash
|
@@ -62,65 +62,68 @@ module RForce
|
|
62
62
|
self[method]
|
63
63
|
end
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
#Turns an XML response from the server into a Ruby
|
67
67
|
#object whose methods correspond to nested XML elements.
|
68
68
|
class SoapResponse
|
69
69
|
include FlashHash
|
70
|
-
|
70
|
+
|
71
71
|
#Parses an XML string into structured data.
|
72
72
|
def initialize(content)
|
73
73
|
document = REXML::Document.new content
|
74
74
|
node = REXML::XPath.first document, '//soapenv:Body'
|
75
75
|
@parsed = SoapResponse.parse node
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
#Allows this object to act like a hash (and therefore
|
79
79
|
#as a FlashHash via the include above).
|
80
80
|
def [](symbol)
|
81
81
|
@parsed[symbol]
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
84
|
#Digests an XML DOM node into nested Ruby types.
|
85
85
|
def SoapResponse.parse(node)
|
86
86
|
#Convert text nodes into simple strings.
|
87
87
|
return node.text unless node.has_elements?
|
88
|
-
|
88
|
+
|
89
89
|
#Convert nodes with children into FlashHashes.
|
90
90
|
elements = {}
|
91
91
|
class << elements
|
92
92
|
include FlashHash
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
95
|
#Add all the element's children to the hash.
|
96
96
|
node.each_element do |e|
|
97
97
|
name = e.name.to_sym
|
98
98
|
|
99
99
|
case elements[name]
|
100
100
|
#The most common case: unique child element tags.
|
101
|
-
|
101
|
+
when NilClass: elements[name] = parse(e)
|
102
102
|
|
103
103
|
#Non-unique child elements become arrays:
|
104
104
|
|
105
105
|
#We've already created the array: just
|
106
106
|
#add the element.
|
107
|
-
|
107
|
+
when Array: elements[name] << parse(e)
|
108
108
|
|
109
109
|
#We haven't created the array yet: do so,
|
110
110
|
#then put the existing element in, followed
|
111
111
|
#by the new one.
|
112
|
-
|
113
|
-
|
114
|
-
|
112
|
+
else
|
113
|
+
elements[name] = [elements[name]]
|
114
|
+
elements[name] << parse(e)
|
115
115
|
end
|
116
116
|
end
|
117
|
-
|
117
|
+
|
118
118
|
return elements
|
119
119
|
end
|
120
120
|
end
|
121
|
-
|
121
|
+
|
122
122
|
#Implements the connection to the SalesForce server.
|
123
123
|
class Binding
|
124
|
+
DEFAULT_BATCH_SIZE = 10
|
125
|
+
attr_accessor :batch_size
|
126
|
+
|
124
127
|
#Fill in the guts of this typical SOAP envelope
|
125
128
|
#with the session ID and the body of the SOAP request.
|
126
129
|
Envelope = <<-HERE
|
@@ -132,13 +135,16 @@ module RForce
|
|
132
135
|
<SessionHeader>
|
133
136
|
<sessionId>%s</sessionId>
|
134
137
|
</SessionHeader>
|
138
|
+
<QueryOptions>
|
139
|
+
<batchSize>%d</batchSize>
|
140
|
+
</QueryOptions>
|
135
141
|
</env:Header>
|
136
142
|
<env:Body>
|
137
143
|
%s
|
138
144
|
</env:Body>
|
139
145
|
</env:Envelope>
|
140
146
|
HERE
|
141
|
-
|
147
|
+
|
142
148
|
#Connect to the server securely.
|
143
149
|
def initialize(url)
|
144
150
|
@url = URI.parse(url)
|
@@ -146,21 +152,24 @@ module RForce
|
|
146
152
|
@server.use_ssl = @url.scheme == 'https'
|
147
153
|
|
148
154
|
# run ruby with -d to see SOAP wiredumps.
|
149
|
-
@server.set_debug_output $stderr if $DEBUG
|
155
|
+
@server.set_debug_output $stderr #if $DEBUG
|
150
156
|
|
151
157
|
@session_id = ''
|
158
|
+
@batch_size = DEFAULT_BATCH_SIZE
|
152
159
|
end
|
153
|
-
|
160
|
+
|
161
|
+
|
154
162
|
#Log in to the server and remember the session ID
|
155
163
|
#returned to us by SalesForce.
|
156
164
|
def login(user, pass)
|
157
165
|
response = call_remote(:login, [:username, user, :password, pass])
|
158
|
-
|
166
|
+
|
159
167
|
raise "Incorrect user name / password [#{response.fault}]" unless response.loginResponse
|
160
168
|
@session_id = response.loginResponse.result.sessionId
|
169
|
+
|
161
170
|
response
|
162
171
|
end
|
163
|
-
|
172
|
+
|
164
173
|
#Call a method on the remote server. Arguments can be
|
165
174
|
#a hash or (if order is important) an array of alternating
|
166
175
|
#keys and values.
|
@@ -169,56 +178,59 @@ module RForce
|
|
169
178
|
expanded = ''
|
170
179
|
@builder = Builder::XmlMarkup.new(:target => expanded)
|
171
180
|
expand({method => args}, 'urn:partner.soap.sforce.com')
|
172
|
-
|
181
|
+
|
173
182
|
#Fill in the blanks of the SOAP envelope with our
|
174
183
|
#session ID and the expanded XML of our request.
|
175
|
-
request = (Envelope % [@session_id, expanded])
|
176
|
-
|
184
|
+
request = (Envelope % [@session_id, @batch_size, expanded])
|
185
|
+
|
186
|
+
# reset the batch size for the next request
|
187
|
+
@batch_size = DEFAULT_BATCH_SIZE
|
188
|
+
|
177
189
|
#Send the request to the server and read the response.
|
178
190
|
response = @server.post2(@url.path, request, {'SOAPAction' => method.to_s, 'content-type' => 'text/xml'})
|
179
191
|
SoapResponse.new(response.body)
|
180
192
|
end
|
181
|
-
|
193
|
+
|
182
194
|
#Turns method calls on this object into remote SOAP calls.
|
183
195
|
def method_missing(method, *args)
|
184
196
|
unless args.size == 1 && [Hash, Array].include?(args[0].class)
|
185
197
|
raise 'Expected 1 Hash or Array argument'
|
186
198
|
end
|
187
|
-
|
199
|
+
|
188
200
|
call_remote method, args[0]
|
189
201
|
end
|
190
|
-
|
202
|
+
|
191
203
|
#Expand Ruby data structures into XML.
|
192
204
|
def expand(args, xmlns = nil)
|
193
205
|
#Nest arrays: [:a, 1, :b, 2] => [[:a, 1], [:b, 2]]
|
194
206
|
if (args.class == Array)
|
195
207
|
args.each_index{|i| args[i, 2] = [args[i, 2]]}
|
196
208
|
end
|
197
|
-
|
209
|
+
|
198
210
|
args.each do |key, value|
|
199
211
|
attributes = xmlns ? {:xmlns => xmlns} : {}
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
212
|
+
|
213
|
+
#If the XML tag requires attributes,
|
214
|
+
#the tag name will contain a space
|
215
|
+
#followed by a string representation
|
216
|
+
#of a hash of attributes.
|
217
|
+
#
|
218
|
+
#e.g. 'sObject {"xsi:type" => "Opportunity"}'
|
219
|
+
#becomes <sObject xsi:type="Opportunity>...</sObject>
|
208
220
|
if key.is_a? String
|
209
|
-
|
210
|
-
|
211
|
-
|
221
|
+
key, modifier = key.split(' ', 2)
|
222
|
+
|
223
|
+
attributes.merge!(eval(modifier)) if modifier
|
212
224
|
end
|
213
225
|
|
214
226
|
#Create an XML element and fill it with this
|
215
227
|
#value's sub-items.
|
216
228
|
case value
|
217
|
-
|
218
|
-
|
229
|
+
when Hash, Array
|
230
|
+
@builder.tag!(key, attributes) do expand value; end
|
219
231
|
|
220
|
-
|
221
|
-
|
232
|
+
when String
|
233
|
+
@builder.tag!(key, attributes) { @builder.text! value }
|
222
234
|
end
|
223
235
|
end
|
224
236
|
end
|
@@ -68,6 +68,7 @@ module ActiveRecord
|
|
68
68
|
end
|
69
69
|
|
70
70
|
class SalesforceAdapter < AbstractAdapter
|
71
|
+
attr_accessor :batch_size
|
71
72
|
|
72
73
|
def initialize(connection, logger, connection_options, config)
|
73
74
|
super(connection, logger)
|
@@ -131,7 +132,10 @@ module ActiveRecord
|
|
131
132
|
def select_all(soql, name = nil) #:nodoc:
|
132
133
|
log(soql, name)
|
133
134
|
|
134
|
-
|
135
|
+
@connection.batch_size = @batch_size if @batch_size
|
136
|
+
@batch_size = nil
|
137
|
+
|
138
|
+
records = get_result(@connection.query(:queryString => soql), :query).records
|
135
139
|
|
136
140
|
records = [ records ] unless records.is_a?(Array)
|
137
141
|
|
@@ -150,30 +154,31 @@ module ActiveRecord
|
|
150
154
|
end
|
151
155
|
|
152
156
|
def create(sobject, name = nil) #:nodoc:
|
153
|
-
|
154
|
-
|
155
|
-
raise SalesforceError, result[:errors].message unless result[:success] == "true"
|
156
|
-
|
157
|
-
result[:id]
|
157
|
+
check_result(get_result(@connection.create(sobject), :create))[:id]
|
158
158
|
end
|
159
159
|
|
160
160
|
def update(sobject, name = nil) #:nodoc:
|
161
|
-
|
162
|
-
|
163
|
-
raise SalesforceError, result[:errors].message unless result[:success] == "true"
|
164
|
-
|
165
|
-
# @connection.affected_rows
|
161
|
+
check_result(get_result(@connection.update(sobject), :update))
|
166
162
|
end
|
167
163
|
|
168
164
|
def delete(ids)
|
169
165
|
puts "Delete #{ids}"
|
166
|
+
check_result(get_result(@connection.delete(:ids => ids), :delete))
|
167
|
+
end
|
170
168
|
|
169
|
+
def get_result(response, method)
|
170
|
+
responseName = (method.to_s + "Response").to_sym
|
171
|
+
finalResponse = response[responseName]
|
172
|
+
raise SalesforceError, response.fault unless finalResponse
|
171
173
|
|
172
|
-
result =
|
173
|
-
|
174
|
+
result = finalResponse[:result]
|
175
|
+
end
|
176
|
+
|
177
|
+
def check_result(result)
|
174
178
|
raise SalesforceError, result[:errors].message unless result[:success] == "true"
|
179
|
+
result
|
175
180
|
end
|
176
|
-
|
181
|
+
|
177
182
|
def columns(table_name, name = nil)
|
178
183
|
cached_columns = @columns_map[table_name]
|
179
184
|
return cached_columns if cached_columns
|
@@ -182,8 +187,8 @@ module ActiveRecord
|
|
182
187
|
|
183
188
|
cached_columns = []
|
184
189
|
@columns_map[table_name] = cached_columns
|
185
|
-
|
186
|
-
metadata = @connection.describeSObject(:sObjectType => table_name)
|
190
|
+
|
191
|
+
metadata = get_result(@connection.describeSObject(:sObjectType => table_name), :describeSObject)
|
187
192
|
|
188
193
|
metadata.fields.each do |field|
|
189
194
|
cached_columns << SalesforceColumn.new(field)
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: activesalesforce
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date: 2006-01-
|
6
|
+
version: 0.0.5
|
7
|
+
date: 2006-01-23 00:00:00 -05:00
|
8
8
|
summary: ActiveSalesforce is an extension to the Rails Framework that allows for the dynamic creation and management of ActiveRecord objects through the use of Salesforce meta-data and uses a Salesforce.com organization as the backing store.
|
9
9
|
require_paths:
|
10
10
|
- lib
|