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 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
- when NilClass: elements[name] = parse(e)
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
- when Array: elements[name] << parse(e)
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
- else
113
- elements[name] = [elements[name]]
114
- elements[name] << parse(e)
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
- #If the XML tag requires attributes,
202
- #the tag name will contain a space
203
- #followed by a string representation
204
- #of a hash of attributes.
205
- #
206
- #e.g. 'sObject {"xsi:type" => "Opportunity"}'
207
- #becomes <sObject xsi:type="Opportunity>...</sObject>
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
- key, modifier = key.split(' ', 2)
210
-
211
- attributes.merge!(eval(modifier)) if modifier
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
- when Hash, Array
218
- @builder.tag!(key, attributes) do expand value; end
229
+ when Hash, Array
230
+ @builder.tag!(key, attributes) do expand value; end
219
231
 
220
- when String
221
- @builder.tag!(key, attributes) { @builder.text! value }
232
+ when String
233
+ @builder.tag!(key, attributes) { @builder.text! value }
222
234
  end
223
235
  end
224
236
  end
@@ -133,6 +133,7 @@ module ActiveRecord
133
133
  end
134
134
 
135
135
  def self.count_by_sql(soql)
136
+ connection.batch_size = 1
136
137
  connection.select_all(soql, "#{name} Count").length
137
138
  end
138
139
 
@@ -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
- records = @connection.query(:queryString => soql).queryResponse.result.records
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
- result = @connection.create(sobject).createResponse.result
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
- result = @connection.update(sobject).updateResponse.result
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 = @connection.delete(:ids => ids).deleteResponse.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).describeSObjectResponse.result
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.4
7
- date: 2006-01-22 00:00:00 -05:00
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