activesalesforce 0.2.6 → 0.2.7
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/asf_adapter.rb +53 -31
- data/lib/column_definition.rb +3 -2
- data/lib/mock_binding.rb +76 -0
- data/lib/relationship_definition.rb +21 -8
- data/lib/rforce.rb +4 -4
- data/test/unit/basic_test.rb +99 -0
- data/test/unit/config.yml +4 -0
- data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_add_notes_to_contact.recording +1332 -0
- data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_count_contacts.recording +1161 -0
- data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_create_a_contact.recording +1045 -0
- data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_find_a_contact.recording +1045 -0
- data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_find_a_contact_by_first_name.recording +1099 -0
- data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_find_a_contact_by_id.recording +1099 -0
- data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_get_created_by_from_contact.recording +3019 -0
- data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_read_all_content_columns.recording +1045 -0
- data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_save_a_contact.recording +1045 -0
- data/test/unit/recorded_test_case.rb +118 -0
- metadata +16 -3
- data/test/unit/account_test.rb +0 -107
data/lib/asf_adapter.rb
CHANGED
@@ -44,18 +44,25 @@ module ActiveRecord
|
|
44
44
|
|
45
45
|
# Establishes a connection to the database that's used by all Active Record objects.
|
46
46
|
def self.activesalesforce_connection(config) # :nodoc:
|
47
|
-
puts "
|
47
|
+
puts "\nUsing ActiveSalesforce connection\n"
|
48
48
|
|
49
49
|
url = config[:url]
|
50
50
|
sid = config[:sid]
|
51
|
+
binding = config[:binding] if config[:binding]
|
51
52
|
|
53
|
+
if binding
|
54
|
+
puts " via provided binding #{binding}\n"
|
55
|
+
#pp binding
|
56
|
+
end
|
57
|
+
|
52
58
|
if sid
|
53
|
-
|
54
|
-
|
59
|
+
binding = @@cache["sid=#{sid}"] unless binding
|
60
|
+
|
61
|
+
unless binding
|
55
62
|
puts "Establishing new connection for [sid='#{sid}']"
|
56
63
|
|
57
|
-
|
58
|
-
@@cache["sid=#{sid}"] =
|
64
|
+
binding = RForce::Binding.new(url, sid)
|
65
|
+
@@cache["sid=#{sid}"] = binding
|
59
66
|
|
60
67
|
puts "Created new connection for [sid='#{sid}']"
|
61
68
|
end
|
@@ -71,19 +78,20 @@ module ActiveRecord
|
|
71
78
|
username = config[:username]
|
72
79
|
password = config[:password]
|
73
80
|
|
74
|
-
|
75
|
-
|
81
|
+
binding = @@cache["#{url}.#{username}.#{password}"] unless binding
|
82
|
+
|
83
|
+
unless binding
|
76
84
|
puts "Establishing new connection for ['#{url}', '#{username}']"
|
77
85
|
|
78
|
-
|
79
|
-
|
86
|
+
binding = RForce::Binding.new(url, sid)
|
87
|
+
binding.login(username, password).result
|
80
88
|
|
81
|
-
@@cache["#{url}.#{username}.#{password}"] =
|
89
|
+
@@cache["#{url}.#{username}.#{password}"] = binding
|
82
90
|
|
83
91
|
puts "Created new connection for ['#{url}', '#{username}']"
|
84
92
|
end
|
85
93
|
|
86
|
-
ConnectionAdapters::SalesforceAdapter.new(
|
94
|
+
ConnectionAdapters::SalesforceAdapter.new(binding, logger, [url, username, password, sid], config)
|
87
95
|
end
|
88
96
|
end
|
89
97
|
end
|
@@ -98,7 +106,7 @@ module ActiveRecord
|
|
98
106
|
|
99
107
|
@fault = fault
|
100
108
|
|
101
|
-
logger.debug("\nSalesforceError:\n message='#{message}'\n fault='#{fault}'\n\n")
|
109
|
+
logger.debug("\nSalesforceError:\n message='#{message}'\n fault='#{fault}'\n\n") if logger
|
102
110
|
end
|
103
111
|
end
|
104
112
|
|
@@ -290,8 +298,8 @@ module ActiveRecord
|
|
290
298
|
values = values.scan(/(((NULL))|((TRUE))|((FALSE))|'(([^']|'')*)'),*/mi)
|
291
299
|
|
292
300
|
values.map! { |v| v[7] }
|
293
|
-
|
294
|
-
fields = get_fields(columns, names, values)
|
301
|
+
|
302
|
+
fields = get_fields(columns, names, values, :createable)
|
295
303
|
|
296
304
|
sobject = create_sobject(entity_name, nil, fields)
|
297
305
|
|
@@ -314,7 +322,7 @@ module ActiveRecord
|
|
314
322
|
values = match.scan(/=\s*(((NULL))|((TRUE))|((FALSE))|'(([^']|'')*)'),*/mi)
|
315
323
|
values.map! { |v| v[7] }
|
316
324
|
|
317
|
-
fields = get_fields(columns, names, values)
|
325
|
+
fields = get_fields(columns, names, values, :updateable)
|
318
326
|
|
319
327
|
id = sql.match(/WHERE\s+id\s*=\s*'(\w+)'/i)[1]
|
320
328
|
|
@@ -341,13 +349,11 @@ module ActiveRecord
|
|
341
349
|
ids_element = []
|
342
350
|
ids.each { |id| ids_element << :ids << id }
|
343
351
|
|
344
|
-
pp ids_element
|
345
|
-
|
346
352
|
check_result(get_result(@connection.delete(ids_element), :delete))
|
347
353
|
end
|
348
354
|
|
349
355
|
|
350
|
-
def get_fields(columns, names, values)
|
356
|
+
def get_fields(columns, names, values, access_check)
|
351
357
|
fields = {}
|
352
358
|
names.each_with_index do | name, n |
|
353
359
|
value = values[n]
|
@@ -359,7 +365,8 @@ module ActiveRecord
|
|
359
365
|
|
360
366
|
value.gsub!(/''/, "'") if value.is_a? String
|
361
367
|
|
362
|
-
|
368
|
+
include_field = ((not value.empty?) and column.send(access_check))
|
369
|
+
fields[column.api_name] = value if include_field
|
363
370
|
end
|
364
371
|
end
|
365
372
|
|
@@ -404,15 +411,18 @@ module ActiveRecord
|
|
404
411
|
custom = true
|
405
412
|
end
|
406
413
|
|
407
|
-
metadata
|
414
|
+
metadata[:fields].each do |field|
|
408
415
|
column = SalesforceColumn.new(field)
|
409
416
|
cached_columns << column
|
410
417
|
|
411
418
|
cached_relationships << SalesforceRelationship.new(field, column) if field[:type] =~ /reference/i
|
412
419
|
end
|
413
420
|
|
414
|
-
|
415
|
-
|
421
|
+
relationships = metadata[:childRelationships]
|
422
|
+
if relationships
|
423
|
+
relationships = [ relationships ] unless relationships.is_a? Array
|
424
|
+
|
425
|
+
relationships.each do |relationship|
|
416
426
|
if relationship[:cascadeDelete] == "true"
|
417
427
|
r = SalesforceRelationship.new(relationship)
|
418
428
|
cached_relationships << r
|
@@ -443,28 +453,40 @@ module ActiveRecord
|
|
443
453
|
referenceName = relationship.name
|
444
454
|
unless self.respond_to? referenceName.to_sym or relationship.reference_to == "Profile"
|
445
455
|
reference_to = relationship.reference_to
|
456
|
+
one_to_many = relationship.one_to_many
|
457
|
+
foreign_key = relationship.foreign_key
|
458
|
+
|
459
|
+
# DCHASMAN TODO Figure out how to handle polymorphic refs (e.g. Note.parent can refer to
|
460
|
+
# Account, Contact, Opportunity, Contract, Asset, Product2, <CustomObject1> ... <CustomObject(n)>
|
461
|
+
if reference_to.is_a? Array
|
462
|
+
puts " Skipping unsupported polymophic one-to-#{one_to_many ? 'many' : 'one' } relationship '#{referenceName}' from #{entity_name} to [#{relationship.reference_to.join(', ')}] using #{foreign_key}"
|
463
|
+
next
|
464
|
+
end
|
465
|
+
|
466
|
+
# Handle references to custom objects
|
467
|
+
if reference_to.match(/__c$/)
|
468
|
+
reference_to.chop!.chop!.chop!
|
469
|
+
reference_to.capitalize!
|
470
|
+
end
|
446
471
|
|
447
472
|
begin
|
448
|
-
reference_to.constantize
|
473
|
+
referenced_klass = reference_to.constantize
|
449
474
|
rescue NameError => e
|
450
475
|
# Automatically create a least a stub for the referenced entity
|
476
|
+
puts " Creating ActiveRecord stub for the referenced entity '#{reference_to}'"
|
477
|
+
|
451
478
|
referenced_klass = klass.class_eval("::#{reference_to} = Class.new(ActiveRecord::Base)")
|
452
|
-
referenced_klass.connection = klass.connection
|
453
|
-
#configure_active_record(get_entity_def(reference_to))
|
454
479
|
|
455
|
-
|
480
|
+
# configure_active_record(get_entity_def(reference_to))
|
456
481
|
end
|
457
|
-
|
458
|
-
one_to_many = relationship.one_to_many
|
459
|
-
foreign_key = relationship.foreign_key
|
460
|
-
|
482
|
+
|
461
483
|
if one_to_many
|
462
484
|
klass.has_many referenceName.to_sym, :class_name => reference_to, :foreign_key => foreign_key, :dependent => false
|
463
485
|
else
|
464
486
|
klass.belongs_to referenceName.to_sym, :class_name => reference_to, :foreign_key => foreign_key, :dependent => false
|
465
487
|
end
|
466
488
|
|
467
|
-
puts "Created one-to-#{one_to_many ? 'many' : 'one' } relationship '#{referenceName}' from #{entity_name} to #{relationship.reference_to} using #{foreign_key}"
|
489
|
+
puts " Created one-to-#{one_to_many ? 'many' : 'one' } relationship '#{referenceName}' from #{entity_name} to #{relationship.reference_to} using #{foreign_key}"
|
468
490
|
|
469
491
|
end
|
470
492
|
end
|
data/lib/column_definition.rb
CHANGED
@@ -38,7 +38,7 @@ module ActiveRecord
|
|
38
38
|
class SalesforceColumn < Column
|
39
39
|
include StringHelper
|
40
40
|
|
41
|
-
attr_reader :api_name, :custom, :label, :
|
41
|
+
attr_reader :api_name, :custom, :label, :createable, :updateable, :reference_to
|
42
42
|
|
43
43
|
def initialize(field)
|
44
44
|
@api_name = field[:name]
|
@@ -51,7 +51,8 @@ module ActiveRecord
|
|
51
51
|
@text = [:string, :text].include? @type
|
52
52
|
@number = [:float, :integer].include? @type
|
53
53
|
|
54
|
-
@
|
54
|
+
@createable = field[:createable] == "true"
|
55
|
+
@updateable = field[:updateable] == "true"
|
55
56
|
|
56
57
|
if field[:type] =~ /reference/i
|
57
58
|
@reference_to = field[:referenceTo]
|
data/lib/mock_binding.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
=begin
|
2
|
+
ActiveSalesforce
|
3
|
+
Copyright (c) 2006 Doug Chasman
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
=end
|
23
|
+
|
24
|
+
require 'yaml'
|
25
|
+
require File.dirname(__FILE__) + '/rforce'
|
26
|
+
|
27
|
+
|
28
|
+
class MockBinding < RForce::Binding
|
29
|
+
attr_reader :recorded_responses
|
30
|
+
|
31
|
+
#Connect to the server securely.
|
32
|
+
def initialize(url, sid, recording)
|
33
|
+
@recording = recording
|
34
|
+
@recorded_responses = {}
|
35
|
+
|
36
|
+
super(url, sid) if @recording
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def save(f)
|
41
|
+
YAML.dump(@recorded_responses, f)
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def load(f)
|
46
|
+
@recorded_responses = YAML.load(f)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
#Call a method on the remote server. Arguments can be
|
51
|
+
#a hash or (if order is important) an array of alternating
|
52
|
+
#keys and values.
|
53
|
+
def call_remote(method, args)
|
54
|
+
# Star-out any passwords
|
55
|
+
safe_args = args.inject([]) {|memo, v| memo << (memo.last == :password ? "*" * v.length : v) }
|
56
|
+
key = "#{method}(#{safe_args.join(':')})"
|
57
|
+
|
58
|
+
if @recording
|
59
|
+
response = super(method, args)
|
60
|
+
@recorded_responses[key] = response
|
61
|
+
else
|
62
|
+
response = @recorded_responses[key]
|
63
|
+
|
64
|
+
unless response
|
65
|
+
@recorded_responses.each do |request, reponse|
|
66
|
+
#pp request
|
67
|
+
end
|
68
|
+
|
69
|
+
raise "Unable to find matching response for recorded request '#{key}'"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
response
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -45,12 +45,28 @@ module ActiveRecord
|
|
45
45
|
if source[:childSObject]
|
46
46
|
relationship = source
|
47
47
|
|
48
|
-
|
49
|
-
|
48
|
+
if relationship[:relationshipName]
|
49
|
+
@api_name = relationship[:relationshipName]
|
50
|
+
@one_to_many = true
|
51
|
+
@label = @api_name
|
52
|
+
@name = column_nameize(@api_name)
|
53
|
+
@custom = false
|
54
|
+
else
|
55
|
+
@api_name = relationship[:field]
|
56
|
+
@one_to_many = relationship[:cascadeDelete] == "true"
|
57
|
+
@label = relationship[:childSObject].pluralize
|
58
|
+
@custom = relationship[:childSObject].match(/__c$/)
|
59
|
+
|
60
|
+
name = relationship[:childSObject]
|
61
|
+
name.chop!.chop!.chop! if custom
|
62
|
+
|
63
|
+
@name = column_nameize(name.pluralize)
|
64
|
+
end
|
65
|
+
|
50
66
|
@reference_to = relationship[:childSObject]
|
51
|
-
|
67
|
+
|
52
68
|
@foreign_key = column_nameize(relationship[:field])
|
53
|
-
@
|
69
|
+
@foreign_key.chop!.chop! << "id__c" if @foreign_key.match(/__c$/)
|
54
70
|
else
|
55
71
|
field = source
|
56
72
|
|
@@ -60,15 +76,12 @@ module ActiveRecord
|
|
60
76
|
@api_name = @api_name.chop.chop unless @custom
|
61
77
|
|
62
78
|
@label = field[:label]
|
63
|
-
@readonly = (field[:updateable] != "true" or field[:createable] != "true")
|
64
79
|
@reference_to = field[:referenceTo]
|
65
80
|
@one_to_many = false
|
66
81
|
|
67
82
|
@foreign_key = column.name
|
83
|
+
@name = column_nameize(@api_name)
|
68
84
|
end
|
69
|
-
|
70
|
-
@name = column_nameize(@api_name)
|
71
|
-
|
72
85
|
end
|
73
86
|
end
|
74
87
|
|
data/lib/rforce.rb
CHANGED
@@ -150,7 +150,7 @@ module RForce
|
|
150
150
|
|
151
151
|
|
152
152
|
#Connect to the server securely.
|
153
|
-
def initialize(url, sid
|
153
|
+
def initialize(url, sid)
|
154
154
|
init_server(url)
|
155
155
|
|
156
156
|
@session_id = sid
|
@@ -184,10 +184,10 @@ module RForce
|
|
184
184
|
|
185
185
|
raise "Incorrect user name / password [#{response.fault}]" unless response.loginResponse
|
186
186
|
|
187
|
-
result = response
|
188
|
-
@session_id = result
|
187
|
+
result = response[:loginResponse][:result]
|
188
|
+
@session_id = result[:sessionId]
|
189
189
|
|
190
|
-
init_server(result
|
190
|
+
init_server(result[:serverUrl])
|
191
191
|
|
192
192
|
response
|
193
193
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
#require_gem 'activesalesforce', '>= 0.2.6'
|
4
|
+
require 'activesalesforce'
|
5
|
+
|
6
|
+
require 'recorded_test_case'
|
7
|
+
require 'pp'
|
8
|
+
|
9
|
+
|
10
|
+
class Contact < ActiveRecord::Base
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
module Asf
|
16
|
+
module UnitTests
|
17
|
+
|
18
|
+
class BasicTest < Test::Unit::TestCase
|
19
|
+
include RecordedTestCase
|
20
|
+
|
21
|
+
attr_reader :contact
|
22
|
+
|
23
|
+
def initialize(test_method_name)
|
24
|
+
super(test_method_name)
|
25
|
+
|
26
|
+
#force_recording :test_get_created_by_from_contact
|
27
|
+
end
|
28
|
+
|
29
|
+
def setup
|
30
|
+
puts "\nStarting test '#{self.class.name.gsub('::', '')}.#{method_name}'"
|
31
|
+
|
32
|
+
super
|
33
|
+
|
34
|
+
@contact = Contact.new
|
35
|
+
contact.first_name = 'DutchTestFirstName'
|
36
|
+
contact.last_name = 'DutchTestLastName'
|
37
|
+
contact.home_phone = '555-555-1212'
|
38
|
+
contact.save
|
39
|
+
|
40
|
+
contact.reload
|
41
|
+
end
|
42
|
+
|
43
|
+
def teardown
|
44
|
+
contact.destroy if contact
|
45
|
+
|
46
|
+
super
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_count_contacts
|
50
|
+
assert_equal 27, Contact.count
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_create_a_contact
|
54
|
+
contact.id
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_save_a_contact
|
58
|
+
contact.id
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_find_a_contact
|
62
|
+
c = Contact.find(contact.id)
|
63
|
+
assert_equal contact.id, c.id
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_find_a_contact_by_id
|
67
|
+
c = Contact.find_by_id(contact.id)
|
68
|
+
assert_equal contact.id, c.id
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_find_a_contact_by_first_name
|
72
|
+
c = Contact.find_by_first_name('DutchTestFirstName')
|
73
|
+
assert_equal contact.id, c.id
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_read_all_content_columns
|
77
|
+
Contact.content_columns.each { |column| contact.send(column.name) }
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_get_created_by_from_contact
|
81
|
+
user = contact.created_by
|
82
|
+
assert_equal contact.created_by_id, user.id
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_add_notes_to_contact
|
86
|
+
n1 = Note.new(:title => "My Title", :body => "My Body")
|
87
|
+
n2 = Note.new(:title => "My Title 2", :body => "My Body 2")
|
88
|
+
|
89
|
+
contact.notes << n1
|
90
|
+
contact.notes << n2
|
91
|
+
|
92
|
+
n1.save
|
93
|
+
n2.save
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|