activesalesforce 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -6,8 +6,24 @@
6
6
 
7
7
  == Getting started
8
8
 
9
- 1. TBD Add in info on editing scripts/generate and scripts/server + database.yml
10
-
9
+ 1. gem install activesalesforce
10
+ 2. if you have not already done so generate your initial rails app using "rails <myappname goes here>"
11
+ 3. edit config/environment.rb and add "require_gem 'activesalesforce'" to the end of the "Rails::Initializer.run do |config|" block, e.g.
12
+
13
+ Rails::Initializer.run do |config|
14
+ ...
15
+
16
+ require_gem 'activesalesforce'
17
+ end
18
+
19
+ 4. edit database.yml
20
+
21
+ adapter: salesforce
22
+ url: <salesforce api server url goes here>
23
+ username: <salesforce user name goes here>
24
+ password: <salesforce password goes here>
25
+
26
+ 5. proceed using standard Rails development techniques!
11
27
 
12
28
  == Description of contents
13
29
 
@@ -0,0 +1,24 @@
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 'salesforce_connection_adapter'
@@ -32,38 +32,37 @@ module ActiveRecord
32
32
  # This behavior can be turned off by setting <tt>ActiveRecord::Base.record_timestamps = false</tt>.
33
33
  # This behavior can use GMT by setting <tt>ActiveRecord::Base.timestamps_gmt = true</tt>
34
34
  module SalesforceRecord
35
- include SOAP, XSD
36
-
37
- NS1 = 'urn:partner.soap.sforce.com'
38
- NS2 = "urn:sobject.partner.soap.sforce.com"
39
35
 
40
36
  def self.append_features(base) # :nodoc:
41
37
  super
42
-
38
+
43
39
  base.class_eval do
44
40
  alias_method :create, :create_with_sforce_api
45
41
  alias_method :update, :update_with_sforce_api
46
42
  end
47
43
  end
48
-
44
+
49
45
  def create_with_sforce_api
50
46
  return if not @attributes.changed?
51
47
  puts "create_with_sforce_api creating #{self.class}"
52
- connection.create(:sObjects => create_sobject())
48
+ id = connection.create(:sObjects => create_sobject())
49
+ self.Id = id
50
+ @attributes.clear_changed!
53
51
  end
54
-
52
+
55
53
  def update_with_sforce_api
56
54
  return if not @attributes.changed?
57
55
  puts "update_with_sforce_api updating #{self.class}('#{self.Id}')"
58
56
  connection.update(:sObjects => create_sobject())
57
+ @attributes.clear_changed!
59
58
  end
60
59
 
61
60
  def create_sobject()
62
61
  fields = @attributes.changed_fields
63
-
62
+
64
63
  sobj = [ 'type { :xmlns => "urn:sobject.partner.soap.sforce.com" }', self.class.name ]
65
64
  sobj << 'Id { :xmlns => "urn:sobject.partner.soap.sforce.com" }' << self.Id if self.Id
66
-
65
+
67
66
  # now add any changed fields
68
67
  fieldValues = {}
69
68
  fields.each do |fieldName|
@@ -73,7 +72,7 @@ module ActiveRecord
73
72
 
74
73
  sobj
75
74
  end
76
-
75
+
77
76
  end
78
77
 
79
78
  class Base
@@ -83,16 +82,29 @@ module ActiveRecord
83
82
  default_timezone = :utc
84
83
 
85
84
  def after_initialize()
85
+ sfdcObjectName = self.class.table_name
86
86
  if not @attributes.is_a?(Salesforce::SObjectAttributes)
87
- # Insure that SObjectAttributes is always used for our atttributes
87
+ # Insure that SObjectAttributes is always used for our attributes
88
88
  originalAttributes = @attributes
89
89
 
90
- @attributes = Salesforce::SObjectAttributes.new(connection.columns_map(self.class.table_name))
90
+ @attributes = Salesforce::SObjectAttributes.new(connection.columns_map(sfdcObjectName))
91
91
 
92
92
  originalAttributes.each { |name, value| self[name] = value }
93
93
  end
94
+
95
+ # Create relationships for any reference field
96
+ connection.columns(sfdcObjectName).each do |column|
97
+ if column.reference_to
98
+ referenceName = column.name.chop.chop
99
+
100
+ unless self.respond_to? referenceName.to_sym or column.reference_to == "Profile"
101
+ puts "Creating relationship from #{sfdcObjectName} to #{column.reference_to} for #{referenceName}"
102
+ self.class.belongs_to referenceName.to_sym, :class_name => column.reference_to, :foreign_key => column.name, :dependent => false
103
+ end
104
+ end
105
+ end
94
106
  end
95
-
107
+
96
108
  def self.table_name
97
109
  class_name_of_active_record_descendant(self)
98
110
  end
@@ -100,7 +112,7 @@ module ActiveRecord
100
112
  def self.primary_key
101
113
  "Id"
102
114
  end
103
-
115
+
104
116
  def self.construct_finder_sql(options)
105
117
  soql = "SELECT #{column_names.join(', ')} FROM #{table_name} "
106
118
  add_conditions!(soql, options[:conditions])
@@ -114,15 +126,19 @@ module ActiveRecord
114
126
  end
115
127
 
116
128
  def self.count(conditions = nil, joins = nil)
117
- soql = "SELECT Id FROM #{table_name} "
118
- add_conditions!(soql, conditions)
119
-
120
- count_by_sql(soql)
129
+ soql = "SELECT Id FROM #{table_name} "
130
+ add_conditions!(soql, conditions)
131
+
132
+ count_by_sql(soql)
121
133
  end
122
134
 
123
135
  def self.count_by_sql(soql)
124
136
  connection.select_all(soql, "#{name} Count").length
125
- end
126
-
137
+ end
138
+
139
+ def self.delete(ids)
140
+ connection.delete(ids)
141
+ end
142
+
127
143
  end
128
144
  end
@@ -32,63 +32,63 @@ require File.dirname(__FILE__) + '/salesforce_active_record'
32
32
  require File.dirname(__FILE__) + '/column_definition'
33
33
 
34
34
  ActiveRecord::Base.class_eval do
35
- include ActiveRecord::SalesforceRecord
35
+ include ActiveRecord::SalesforceRecord
36
36
  end
37
37
 
38
38
 
39
39
  module ActiveRecord
40
40
  class Base
41
41
  @@cache = {}
42
-
42
+
43
43
  # Establishes a connection to the database that's used by all Active Record objects.
44
44
  def self.salesforce_connection(config) # :nodoc:
45
45
  puts "Using Salesforce connection!"
46
-
46
+
47
47
  config = config.symbolize_keys
48
-
48
+
49
49
  url = config[:url].to_s
50
50
  username = config[:username].to_s
51
51
  password = config[:password].to_s
52
52
 
53
53
  connection = @@cache["#{url}.#{username}.#{password}"]
54
-
54
+
55
55
  if not connection
56
56
  connection = SalesforceLogin.new(url, username, password).proxy
57
57
  @@cache["#{url}.#{username}.#{password}"] = connection
58
58
  puts "Created new connection for [#{url}, #{username}]"
59
59
  end
60
-
61
- #puts "connected to Salesforce as #{connection.getUserInfo(nil).result['userFullName']}"
62
60
 
63
61
  ConnectionAdapters::SalesforceAdapter.new(connection, logger, [url, username, password], config)
64
62
  end
65
63
  end
66
64
 
67
-
65
+
68
66
  module ConnectionAdapters
69
67
  class SalesforceError < StandardError
70
68
  end
71
69
 
72
70
  class SalesforceAdapter < AbstractAdapter
73
-
71
+
74
72
  def initialize(connection, logger, connection_options, config)
75
73
  super(connection, logger)
76
74
 
77
75
  @connection_options, @config = connection_options, config
76
+
77
+ @columns_map = {}
78
78
  @columns_name_map = {}
79
79
  end
80
-
80
+
81
81
  def adapter_name #:nodoc:
82
82
  'Salesforce'
83
83
  end
84
-
84
+
85
85
  def supports_migrations? #:nodoc:
86
86
  false
87
87
  end
88
-
89
-
88
+
89
+
90
90
  # QUOTING ==================================================
91
-
91
+
92
92
  def quote(value, column = nil)
93
93
  if value.kind_of?(String) && column && column.type == :binary
94
94
  s = column.class.string_to_binary(value).unpack("H*")[0]
@@ -97,15 +97,15 @@ module ActiveRecord
97
97
  super
98
98
  end
99
99
  end
100
-
100
+
101
101
  def quote_column_name(name) #:nodoc:
102
102
  "`#{name}`"
103
103
  end
104
-
104
+
105
105
  def quote_string(string) #:nodoc:
106
106
  string
107
107
  end
108
-
108
+
109
109
  def quoted_true
110
110
  "TRUE"
111
111
  end
@@ -113,28 +113,28 @@ module ActiveRecord
113
113
  def quoted_false
114
114
  "FALSE"
115
115
  end
116
-
117
-
116
+
117
+
118
118
  # CONNECTION MANAGEMENT ====================================
119
-
119
+
120
120
  def active?
121
121
  true
122
122
  end
123
-
123
+
124
124
  def reconnect!
125
125
  connect
126
126
  end
127
-
128
-
127
+
128
+
129
129
  # DATABASE STATEMENTS ======================================
130
-
130
+
131
131
  def select_all(soql, name = nil) #:nodoc:
132
132
  log(soql, name)
133
133
 
134
134
  records = @connection.query(:queryString => soql).queryResponse.result.records
135
135
 
136
136
  records = [ records ] unless records.is_a?(Array)
137
-
137
+
138
138
  result = []
139
139
  records.each do |record|
140
140
  attributes = Salesforce::SObjectAttributes.new(columns_map(record[:type]), record)
@@ -143,46 +143,59 @@ module ActiveRecord
143
143
 
144
144
  result
145
145
  end
146
-
146
+
147
147
  def select_one(sql, name = nil) #:nodoc:
148
148
  result = select_all(sql, name)
149
149
  result.nil? ? nil : result.first
150
150
  end
151
-
151
+
152
152
  def create(sobject, name = nil) #:nodoc:
153
153
  result = @connection.create(sobject).createResponse.result
154
154
 
155
- raise SalesforceError, result.errors.message unless result.success == "true"
155
+ raise SalesforceError, result[:errors].message unless result[:success] == "true"
156
156
 
157
- # @connection.affected_rows
157
+ result[:id]
158
158
  end
159
159
 
160
160
  def update(sobject, name = nil) #:nodoc:
161
161
  result = @connection.update(sobject).updateResponse.result
162
-
163
- raise SalesforceError, result.errors.message unless result.success == "true"
162
+
163
+ raise SalesforceError, result[:errors].message unless result[:success] == "true"
164
164
 
165
165
  # @connection.affected_rows
166
166
  end
167
-
168
- alias_method :delete, :update
169
167
 
168
+ def delete(ids)
169
+ puts "Delete #{ids}"
170
+
171
+
172
+ result = @connection.delete(:ids => ids).deleteResponse.result
173
+
174
+ raise SalesforceError, result[:errors].message unless result[:success] == "true"
175
+ end
176
+
170
177
  def columns(table_name, name = nil)
171
- columns = []
178
+ cached_columns = @columns_map[table_name]
179
+ return cached_columns if cached_columns
180
+
181
+ puts "describeSObject(#{table_name})"
182
+
183
+ cached_columns = []
184
+ @columns_map[table_name] = cached_columns
172
185
 
173
186
  metadata = @connection.describeSObject(:sObjectType => table_name).describeSObjectResponse.result
174
187
 
175
188
  metadata.fields.each do |field|
176
- columns << SalesforceColumn.new(field)
189
+ cached_columns << SalesforceColumn.new(field)
177
190
  end
178
191
 
179
- columns
192
+ cached_columns
180
193
  end
181
-
194
+
182
195
  def columns_map(table_name, name = nil)
183
196
  columns_map = @columns_name_map[table_name]
184
197
  return columns_map if columns_map
185
-
198
+
186
199
  columns_map = {}
187
200
  @columns_name_map[table_name] = columns_map
188
201
 
@@ -190,23 +203,23 @@ module ActiveRecord
190
203
 
191
204
  columns_map
192
205
  end
193
-
206
+
194
207
  private
195
-
196
- def select(sql, name = nil)
197
- puts "select(#{sql}, (#{name}))"
198
- @connection.query_with_result = true
199
- result = execute(sql, name)
200
- rows = []
201
- if @null_values_in_each_hash
202
- result.each_hash { |row| rows << row }
203
- else
204
- all_fields = result.fetch_fields.inject({}) { |fields, f| fields[f.name] = nil; fields }
205
- result.each_hash { |row| rows << all_fields.dup.update(row) }
206
- end
207
- result.free
208
- rows
208
+
209
+ def select(sql, name = nil)
210
+ puts "select(#{sql}, (#{name}))"
211
+ @connection.query_with_result = true
212
+ result = execute(sql, name)
213
+ rows = []
214
+ if @null_values_in_each_hash
215
+ result.each_hash { |row| rows << row }
216
+ else
217
+ all_fields = result.fetch_fields.inject({}) { |fields, f| fields[f.name] = nil; fields }
218
+ result.each_hash { |row| rows << all_fields.dup.update(row) }
209
219
  end
220
+ result.free
221
+ rows
222
+ end
210
223
  end
211
224
  end
212
225
  end
@@ -1,17 +1,14 @@
1
1
  require File.join(File.dirname(__FILE__), '../../config/boot')
2
-
3
- require_gem 'activesalesforce'
4
- require 'salesforce_connection_adapter'
5
-
6
2
  require File.dirname(__FILE__) + '/../test_helper'
7
3
 
8
-
4
+ require 'pp'
9
5
 
10
6
  class AccountTest < Test::Unit::TestCase
11
7
  def setup
12
8
  ActiveRecord::Base.allow_concurrency = true
13
9
  end
14
10
 
11
+
15
12
  def test_get_account
16
13
  accounts = Account.find(:all)
17
14
 
@@ -33,12 +30,37 @@ class AccountTest < Test::Unit::TestCase
33
30
 
34
31
  acme.save
35
32
  end
33
+
36
34
 
37
35
  def test_create_account
38
36
  dutchCo = Account.new
39
37
  dutchCo.Name = "DutchCo"
40
38
  dutchCo.Website = "www.dutchco.com"
41
39
  dutchCo.save
40
+
41
+ dutchCo2 = Account.new(:Name => "DutchCo2", :Website => "www.dutchco2.com")
42
+ dutchCo2.save
43
+
44
+ dutchCo3 = Account.create(:Name => "DutchCo3", :Website => "www.dutchco3.com")
45
+
46
+ accounts = Account.create([
47
+ { :Name => "DutchCo4", :Website => "www.dutchco4.com" },
48
+ { :Name => "DutchCo5", :Website => "www.dutchco5.com" }])
42
49
  end
43
-
50
+
51
+
52
+ def test_destroy_account
53
+ account = Account.create(:Name => "DutchADelete", :Website => "www.dutchcodelete.com")
54
+ account = Account.find_by_Id(account.Id)
55
+
56
+ pp account.Parent
57
+
58
+ puts "Getting CreatedBy"
59
+ createdBy = account.CreatedBy
60
+ createdBy = User.find_by_Id(account.CreatedById);
61
+ puts createdBy.Email
62
+
63
+ Account.delete(account.Id)
64
+ end
65
+
44
66
  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.0.3
7
- date: 2006-01-20 00:00:00 -05:00
6
+ version: 0.0.4
7
+ date: 2006-01-22 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
@@ -12,7 +12,7 @@ email: dchasman@salesforce.com
12
12
  homepage: http://rubyforge.org/projects/activesfdc/
13
13
  rubyforge_project:
14
14
  description:
15
- autorequire: salesforce_connection_adapter
15
+ autorequire: active_salesforce
16
16
  default_executable:
17
17
  bindir: bin
18
18
  has_rdoc: true
@@ -31,6 +31,7 @@ files:
31
31
  - lib/salesforce_login.rb
32
32
  - lib/salesforce_active_record.rb
33
33
  - lib/column_definition.rb
34
+ - lib/activesalesforce.rb
34
35
  - lib/rforce.rb
35
36
  - lib/sobject_attributes.rb
36
37
  - lib/salesforce_connection_adapter.rb