activesalesforce 0.1.7 → 0.1.8
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 +1 -0
- data/lib/salesforce_connection_adapter.rb +82 -62
- metadata +2 -2
data/lib/rforce.rb
CHANGED
@@ -163,6 +163,7 @@ module RForce
|
|
163
163
|
@url = URI.parse(url)
|
164
164
|
@server = Net::HTTP.new(@url.host, @url.port)
|
165
165
|
@server.use_ssl = @url.scheme == 'https'
|
166
|
+
@server.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
166
167
|
|
167
168
|
# run ruby with -d to see SOAP wiredumps.
|
168
169
|
@server.set_debug_output $stderr if show_debug
|
@@ -73,28 +73,50 @@ module ActiveRecord
|
|
73
73
|
|
74
74
|
@fault = fault
|
75
75
|
|
76
|
-
puts "\nSalesforceError:\n message='#{message}'\n fault='#{fault}'\n\n"
|
76
|
+
#puts "\nSalesforceError:\n message='#{message}'\n fault='#{fault}'\n\n"
|
77
77
|
logger.debug("\nSalesforceError:\n message='#{message}'\n fault='#{fault}'\n\n")
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
+
|
81
82
|
class SalesforceAdapter < AbstractAdapter
|
83
|
+
|
84
|
+
class EntityDefinition
|
85
|
+
attr_reader :name, :columns, :column_name_to_column, :relationships
|
86
|
+
|
87
|
+
def custom?
|
88
|
+
@custom
|
89
|
+
end
|
90
|
+
|
91
|
+
def api_name
|
92
|
+
@custom ? name + "__c" : name
|
93
|
+
end
|
94
|
+
|
95
|
+
def initialize(name, columns, relationships, custom)
|
96
|
+
@name = name
|
97
|
+
@columns = columns
|
98
|
+
@relationships = relationships
|
99
|
+
@custom = custom
|
100
|
+
|
101
|
+
@column_name_to_column = {}
|
102
|
+
@columns.each { |column| @column_name_to_column[column.name] = column }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
82
106
|
COLUMN_NAME_REGEX = /@C_(\w+)/
|
83
107
|
COLUMN_VALUE_REGEX = /@V_'(([^']|\\')*)'/
|
84
108
|
|
85
109
|
include StringHelper
|
86
110
|
|
87
111
|
attr_accessor :batch_size
|
112
|
+
attr_reader :entity_def_map
|
88
113
|
|
89
114
|
def initialize(connection, logger, connection_options, config)
|
90
115
|
super(connection, logger)
|
91
116
|
|
92
117
|
@connection_options, @config = connection_options, config
|
93
118
|
|
94
|
-
@
|
95
|
-
@columns_name_map = {}
|
96
|
-
|
97
|
-
@relationships_map = {}
|
119
|
+
@entity_def_map = {}
|
98
120
|
end
|
99
121
|
|
100
122
|
|
@@ -142,11 +164,18 @@ module ActiveRecord
|
|
142
164
|
# DATABASE STATEMENTS ======================================
|
143
165
|
|
144
166
|
def select_all(sql, name = nil) #:nodoc:
|
145
|
-
|
167
|
+
log(sql, name)
|
168
|
+
|
169
|
+
raw_table_name = sql.match(/FROM (\w+) /)[1]
|
170
|
+
table_name = raw_table_name.singularize
|
146
171
|
entity_name = entity_name_from_table(table_name)
|
172
|
+
entity_def = get_entity_def(entity_name)
|
173
|
+
|
147
174
|
column_names = api_column_names(table_name)
|
148
175
|
|
149
|
-
soql = sql.sub(/SELECT \* FROM
|
176
|
+
soql = sql.sub(/SELECT \* FROM /, "SELECT #{column_names.join(', ')} FROM ")
|
177
|
+
|
178
|
+
soql.sub!(/ FROM \w+ /, " FROM #{entity_def.api_name} ")
|
150
179
|
|
151
180
|
# Look for a LIMIT clause
|
152
181
|
soql.sub!(/LIMIT 1/, "")
|
@@ -161,6 +190,9 @@ module ActiveRecord
|
|
161
190
|
soql = $~.pre_match + column.api_name + $~.post_match
|
162
191
|
end
|
163
192
|
|
193
|
+
# Update table name references
|
194
|
+
soql.sub!(/#{raw_table_name}\./, "#{entity_def.api_name}.")
|
195
|
+
|
164
196
|
# Remove column value prefix
|
165
197
|
soql.gsub!(/@V_/, "")
|
166
198
|
|
@@ -182,14 +214,15 @@ module ActiveRecord
|
|
182
214
|
|
183
215
|
record.each do |name, value|
|
184
216
|
name = column_nameize(name.to_s)
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
217
|
+
if name != "type"
|
218
|
+
# Replace nil element with nil
|
219
|
+
value = nil if value.respond_to?(:xmlattr_nil) and value.xmlattr_nil
|
220
|
+
|
221
|
+
# Ids are returned in an array with 2 duplicate entries...
|
222
|
+
value = value[0] if name == "id"
|
223
|
+
|
224
|
+
row[name] = value
|
225
|
+
end
|
193
226
|
end
|
194
227
|
|
195
228
|
result << row
|
@@ -203,11 +236,13 @@ module ActiveRecord
|
|
203
236
|
self.batch_size = 1
|
204
237
|
|
205
238
|
# Check for SELECT COUNT(*) FROM query
|
206
|
-
matchCount = sql.match(/SELECT COUNT\(\*\) FROM
|
239
|
+
matchCount = sql.match(/SELECT COUNT\(\*\) FROM /)
|
207
240
|
if matchCount
|
208
|
-
sql = "SELECT id FROM #{matchCount
|
241
|
+
sql = "SELECT id FROM #{matchCount.post_match}"
|
209
242
|
end
|
210
243
|
|
244
|
+
log(sql, name)
|
245
|
+
|
211
246
|
result = select_all(sql, name)
|
212
247
|
|
213
248
|
if matchCount
|
@@ -289,7 +324,7 @@ module ActiveRecord
|
|
289
324
|
responseName = (method.to_s + "Response").to_sym
|
290
325
|
finalResponse = response[responseName]
|
291
326
|
|
292
|
-
raise SalesforceError.new(@logger, response[:
|
327
|
+
raise SalesforceError.new(@logger, response[:Fault][:faultstring], response.fault) unless finalResponse
|
293
328
|
|
294
329
|
result = finalResponse[:result]
|
295
330
|
end
|
@@ -306,20 +341,22 @@ module ActiveRecord
|
|
306
341
|
end
|
307
342
|
|
308
343
|
|
309
|
-
def
|
310
|
-
|
311
|
-
|
312
|
-
cached_columns = @columns_map[entity_name]
|
313
|
-
return cached_columns if cached_columns
|
344
|
+
def get_entity_def(entity_name)
|
345
|
+
cached_entity_def = @entity_def_map[entity_name]
|
346
|
+
return cached_entity_def if cached_entity_def
|
314
347
|
|
315
348
|
cached_columns = []
|
316
|
-
@columns_map[entity_name] = cached_columns
|
317
|
-
|
318
349
|
cached_relationships = []
|
319
|
-
@relationships_map[entity_name] = cached_relationships
|
320
|
-
|
321
|
-
metadata = get_result(@connection.describeSObject(:sObjectType => entity_name), :describeSObject)
|
322
350
|
|
351
|
+
begin
|
352
|
+
metadata = get_result(@connection.describeSObject(:sObjectType => entity_name), :describeSObject)
|
353
|
+
custom = false
|
354
|
+
rescue SalesforceError => e
|
355
|
+
# Fallback and see if we can find a custom object with this name
|
356
|
+
metadata = get_result(@connection.describeSObject(:sObjectType => entity_name + "__c"), :describeSObject)
|
357
|
+
custom = true
|
358
|
+
end
|
359
|
+
|
323
360
|
metadata.fields.each do |field|
|
324
361
|
column = SalesforceColumn.new(field)
|
325
362
|
cached_columns << column
|
@@ -340,24 +377,27 @@ module ActiveRecord
|
|
340
377
|
end
|
341
378
|
end
|
342
379
|
end
|
380
|
+
|
381
|
+
entity_def = EntityDefinition.new(entity_name, cached_columns, cached_relationships, custom)
|
382
|
+
@entity_def_map[entity_name] = entity_def
|
343
383
|
|
344
|
-
configure_active_record
|
345
|
-
|
346
|
-
|
384
|
+
configure_active_record entity_def
|
385
|
+
|
386
|
+
entity_def
|
347
387
|
end
|
348
388
|
|
349
389
|
|
350
|
-
def configure_active_record(
|
390
|
+
def configure_active_record(entity_def)
|
391
|
+
entity_name = entity_def.name
|
351
392
|
klass = entity_name.constantize
|
352
|
-
|
353
|
-
klass.pluralize_table_names = false
|
393
|
+
|
354
394
|
klass.set_inheritance_column nil
|
355
395
|
klass.lock_optimistically = false
|
356
396
|
klass.record_timestamps = false
|
357
397
|
klass.default_timezone = :utc
|
358
398
|
|
359
399
|
# Create relationships for any reference field
|
360
|
-
|
400
|
+
entity_def.relationships.each do |relationship|
|
361
401
|
referenceName = relationship.name
|
362
402
|
unless self.respond_to? referenceName.to_sym or relationship.reference_to == "Profile"
|
363
403
|
reference_to = relationship.reference_to
|
@@ -387,32 +427,15 @@ module ActiveRecord
|
|
387
427
|
end
|
388
428
|
|
389
429
|
|
390
|
-
def
|
430
|
+
def columns(table_name, name = nil)
|
391
431
|
entity_name = entity_name_from_table(table_name)
|
392
|
-
|
393
|
-
cached_relationships = @relationships_map[entity_name]
|
394
|
-
|
395
|
-
unless cached_relationships
|
396
|
-
# This will load column and relationship metadata
|
397
|
-
columns(table_name)
|
398
|
-
end
|
399
|
-
|
400
|
-
@relationships_map[entity_name]
|
432
|
+
get_entity_def(entity_name).columns
|
401
433
|
end
|
402
|
-
|
434
|
+
|
403
435
|
|
404
436
|
def columns_map(table_name, name = nil)
|
405
437
|
entity_name = entity_name_from_table(table_name)
|
406
|
-
|
407
|
-
columns_map = @columns_name_map[entity_name]
|
408
|
-
unless columns_map
|
409
|
-
columns_map = {}
|
410
|
-
@columns_name_map[entity_name] = columns_map
|
411
|
-
|
412
|
-
columns(entity_name).each { |column| columns_map[column.name] = column }
|
413
|
-
end
|
414
|
-
|
415
|
-
columns_map
|
438
|
+
get_entity_def(entity_name).column_name_to_column
|
416
439
|
end
|
417
440
|
|
418
441
|
|
@@ -422,7 +445,9 @@ module ActiveRecord
|
|
422
445
|
|
423
446
|
|
424
447
|
def create_sobject(entity_name, id, fields)
|
425
|
-
|
448
|
+
entity_def = get_entity_def(entity_name)
|
449
|
+
|
450
|
+
sobj = [ 'type { :xmlns => "urn:sobject.partner.soap.sforce.com" }', entity_def.api_name ]
|
426
451
|
sobj << 'Id { :xmlns => "urn:sobject.partner.soap.sforce.com" }' << id if id
|
427
452
|
|
428
453
|
# now add any changed fields
|
@@ -435,11 +460,6 @@ module ActiveRecord
|
|
435
460
|
end
|
436
461
|
|
437
462
|
|
438
|
-
def table_name_from_sql(sql)
|
439
|
-
sql.match(/FROM (\w+) /)[1].singularize
|
440
|
-
end
|
441
|
-
|
442
|
-
|
443
463
|
def column_names(table_name)
|
444
464
|
columns(table_name).map { |column| column.name }
|
445
465
|
end
|
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.1.
|
7
|
-
date: 2006-02-
|
6
|
+
version: 0.1.8
|
7
|
+
date: 2006-02-04 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
|