Skip to content

Loading…

support for FieldName__c #4

Closed
wants to merge 13 commits into from

2 participants

@twobitfool

Currently the adapter supports:

  • field_name
  • FieldName
  • field_name__c

FieldName__c has shown up a lot in my travels, and it seems like a reasonable addition to that list.

Thanks.

@jpr5

@two-bit-fool I got this from EngineYard -- can you tell me what circumstances led you to make this change?

@jpr5: The typecast method fires as soon as the property is set, but we don't want to convert it until we are sending values back to Salesforce. Before this change, the following would happen: p Event.gen(:all_day_event => true).all_day_event would respond with 1 instead of true.

@jpr5
CloudCrowd member

@two-bit-fool seems a little heavy-handed .. can you comment on when/how it was getting re-read?

For all the individual spec invocations, I'm thinking of nuking the need to specify full path to spec_helper - that way require 'spec/spec_helper' (or whatever) will only ever load it once. Is this really what led to the above?

@jpr5: My bad. This was needed because of the way that I was requiring spec_helper with a relative path, an old, bad habit. Reverted in commit 1102b33.

@jpr5
CloudCrowd member

@two-bit-fool I think cloudcrowd/dm-salesforce-adapter commit 3578230 might obviate this and your commit 6f19c22, FWIW.

@jpr5: I was originally doing this so I could run the spec directly (i.e. ruby some_spec.rb), but I don't do that anymore. I've changed it in commit 66d26ce. Thanks.

twobitfool added some commits
@twobitfool twobitfool avoid relative paths in require spec_helper
it's not needed (unless you want to run the spec directly)
and since the path is not expanded, the spec_helper runs multiple times
66d26ce
@twobitfool twobitfool Revert "prevent spec_helper from re-initializing"
This reverts commit 6f19c22.
1102b33
@jpr5
CloudCrowd member

The equivalent of this is now in the main cloudcrowd repository, FYI.

cloudcrowd@e8db767

@jpr5 jpr5 closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 11, 2011
  1. @twobitfool
Commits on Jul 21, 2011
  1. @twobitfool

    Merge branch 'cloudcrowd'

    twobitfool committed
    Conflicts:
    	dm-salesforce-adapter.gemspec
Commits on Jul 25, 2011
  1. @twobitfool

    also check for FieldName__c

    twobitfool committed
  2. @twobitfool
  3. @twobitfool

    require spec_helper from each spec

    twobitfool committed
    This allows rake spec SPEC=/some/spec/path.rb
  4. @twobitfool
  5. @twobitfool

    use 18 character long ids

    twobitfool committed
  6. @twobitfool
Commits on Jul 26, 2011
  1. @twobitfool
  2. @twobitfool
  3. @twobitfool
Commits on Sep 11, 2011
  1. @twobitfool

    avoid relative paths in require spec_helper

    twobitfool committed
    it's not needed (unless you want to run the spec directly)
    and since the path is not expanded, the spec_helper runs multiple times
  2. @twobitfool

    Revert "prevent spec_helper from re-initializing"

    twobitfool committed
    This reverts commit 6f19c22.
View
16 lib/dm-salesforce-adapter/adapter.rb
@@ -34,6 +34,9 @@ def connection
# Needs to be applied to all CRUD operations.
def create(resources)
arr = resources.map do |resource|
+ if DataMapper.logger
+ DataMapper.logger.debug "SalesforceAdapter - Create: #{resource.class.name} #{Hash[resource.dirty_attributes.map{|prop, value| [prop.name, value]}].inspect}"
+ end
make_salesforce_obj(resource, resource.dirty_attributes)
end
@@ -54,7 +57,12 @@ def create(resources)
def update(attributes, collection)
query = collection.query
- arr = collection.map { |obj| make_salesforce_obj(query, attributes) }
+ arr = collection.map { |obj|
+ if DataMapper.logger
+ DataMapper.logger.debug "SalesforceAdapter - Update: #{query.model} #{Hash[attributes.map{|prop, value| [prop.name, value]}].inspect}"
+ end
+ make_salesforce_obj(query, attributes)
+ }
connection.update(arr).size
@@ -66,6 +74,8 @@ def delete(collection)
query = collection.query
keys = collection.map { |r| r.key }.flatten.uniq
+ DataMapper.logger.debug "SalesforceAdapter - Delete: #{query.model} #{keys.map(&:to_s).join(", ")}" if DataMapper.logger
+
connection.delete(keys).size
rescue Connection::SOAPError => e
@@ -139,7 +149,7 @@ def execute_select(query)
sql << " ORDER BY #{order(query.order[0])}" unless query.order.nil? or query.order.empty?
sql << " LIMIT #{query.limit}" if query.limit
- DataMapper.logger.debug sql if DataMapper.logger
+ DataMapper.logger.debug "SalesforceAdapter - #{sql}" if DataMapper.logger
connection.query(sql)
end
@@ -165,7 +175,7 @@ def make_salesforce_obj(from, with_attrs)
def normalize_id_value(klass, property, value)
return nil unless value
properties = Array(klass.send(:salesforce_id_properties)).map { |p| p.to_sym } rescue []
- return properties.include?(property.name) ? value[0..14] : value
+ return properties.include?(property.name) ? value[0..17] : value
end
end
View
6 lib/dm-salesforce-adapter/connection.rb
@@ -49,14 +49,14 @@ def make_object(klass_name, values)
def field_name_for(klass_name, column)
klass = SalesforceAPI.const_get(klass_name)
- fields = [column, Inflector.camelize(column.to_s), "#{column}__c".downcase]
+ fields = [column, Inflector.camelize(column.to_s), "#{Inflector.camelize(column.to_s)}__c", "#{column}__c".downcase]
options = /^(#{fields.join("|")})$/i
matches = klass.instance_methods(false).grep(options)
if matches.any?
matches.first
else
raise FieldNotFound,
- "You specified #{column} as a field, but neither #{fields.join(" or ")} exist. " \
+ "You specified #{column} as a field, but none of the expected field names exist: #{fields.join(", ")}. " \
"Either manually specify the field name with :field, or check to make sure you have " \
"provided a correct field name."
end
@@ -97,7 +97,7 @@ def login
begin
result = driver.login(:username => @username, :password => @password).result
rescue SOAP::FaultError => error
- if error.faultcode.to_s =~ /INVALID_LOGIN/
+ if error.to_s =~ /INVALID_LOGIN/
raise LoginFailed, error.faultstring.to_s
else
raise error
View
2 lib/dm-salesforce-adapter/property/boolean.rb
@@ -7,7 +7,7 @@ def load(value)
[true, 1, '1', 'true', 'TRUE'].include?(value) ? true : false
end
- def typecast(value)
+ def dump(value)
[true, 1, '1', 'true', 'TRUE'].include?(value) ? TRUE : FALSE
end
View
4 lib/dm-salesforce-adapter/property/serial.rb
@@ -3,10 +3,10 @@ class Serial < ::DataMapper::Property::String
accept_options :serial
serial true
- length 15
+ length 18
def dump(value)
- value[0..14] unless value.blank?
+ value.to_s[0..17]
end
end
end
View
31 spec/connection/login_spec.rb
@@ -1,39 +1,30 @@
+require 'spec/spec_helper'
+
module DataMapper::Salesforce
describe "Using the raw connection" do
describe "when authenticating without an organization id" do
+
describe "with the correct credentials" do
+
it "succeeds" do
db = ::DataMapper.repository(:salesforce).adapter.connection
- Connection.new(VALID_USER.username, VALID_USER.password, db.wsdl_path, db.api_dir)
+ SalesforceAdapter::Connection.new(VALID_USERNAME, VALID_PASSWORD, db.wsdl_path, db.api_dir)
end
+
end
+
describe "with an invalid password" do
+
it "fails to login" do
db = ::DataMapper.repository(:salesforce).adapter.connection
- lambda { Connection.new(VALID_USER.username, 'bad-password', db.wsdl_path, db.api_dir) }.
- should raise_error(Connection::LoginFailed)
+ lambda {
+ SalesforceAdapter::Connection.new(VALID_USERNAME, 'bad-password', db.wsdl_path, db.api_dir)
+ }.should raise_error(SalesforceAdapter::Connection::Errors::LoginFailed)
end
- end
- end
- describe "when authenticating with an organization id" do
- describe "with the correct self service credentials" do
- it "succeeds" do
- pending "self service is no longer supported"
- db = DataMapper.repository(:salesforce).adapter.connection
- Connection.new(VALID_SELF_SERVICE_USER.username, VALID_SELF_SERVICE_USER.password, db.wsdl_path, db.api_dir, db.organization_id)
- end
end
- describe "with an invalid password" do
- it "fails to login" do
- pending "self service is no longer supported"
- db = DataMapper.repository(:salesforce).adapter.connection
- lambda { Connection.new(VALID_SELF_SERVICE_USER.username, "bad-password", db.wsdl_path, db.api_dir, db.organization_id) }.
- should raise_error(Connection::LoginFailed)
- end
- end
end
end
end
View
11 spec/fixtures/account.rb
@@ -9,18 +9,17 @@ def self.salesforce_id_properties
:id
end
- property :id, Serial
- property :name, String, :required => true
- property :active, Boolean, :field => 'Active_L_C__c'
- property :annual_revenue, Float
- property :number_of_employees, Integer
+ property :id, Serial
+ property :name, String, :required => true
+ property :annual_revenue, Float
+ property :number_of_employees, Integer
+ property :deleted, Boolean, :field => "IsDeleted"
has n, :contacts
end
Account.fix {{
:name => Randgen.first_name,
- :active => true,
:annual_revenue => rand(1_000).to_f / 100,
:number_of_employees => (1..10).pick,
}}
View
4 spec/fixtures/contact.rb
@@ -14,9 +14,6 @@ def self.salesforce_id_properties
property :last_name, String, :required => true
property :email, String, :format => :email_address
property :account_id, String
- property :irc_nick, String, :required => false, :unique => true
- property :active, Boolean
- property :has_opted_out_of_email, Boolean
belongs_to :account
end
@@ -26,5 +23,4 @@ def self.salesforce_id_properties
:last_name => /\w+/.gen,
:email => /\w+@example.com/.gen,
:account => Account.gen,
- :has_opted_out_of_email => [true, false].pick,
}}
View
27 spec/fixtures/event.rb
@@ -0,0 +1,27 @@
+class Event
+ include DataMapper::Salesforce::Resource
+
+ def self.default_repository_name
+ :salesforce
+ end
+
+ def self.salesforce_id_properties
+ [:id, :account_id]
+ end
+
+ property :id, Serial
+ property :subject, String, :required => false, :unique => true
+ property :all_day_event, Boolean, :field => "IsAllDayEvent"
+ property :activity_date, Date, :required => true
+ property :activity_date_time, Time, :required => true
+ property :duration_in_minutes, Integer, :required => true
+end
+
+
+Event.fix {{
+ :subject => /\w+/.gen,
+ :all_day_event => [true, false].pick,
+ :activity_date => Time.local(2011, 1, 1),
+ :activity_date_time => Time.local(2011, 1, 1),
+ :duration_in_minutes => 1440,
+}}
View
22 spec/models/account_spec.rb
@@ -1,11 +1,13 @@
+require 'spec/spec_helper'
+
describe "Account" do
describe "#first" do
#pending "testing first should not be on account"
it "return the first element" do
Account.first.should_not be_nil
end
- it "has a 15 character long id" do
- Account.first.id.size.should == 15
+ it "has a 18 character long id" do
+ Account.first.id.size.should == 18
end
end
@@ -19,16 +21,16 @@
describe "#create" do
it "has errors when omitting the account name" do
- a = Account.create(:active => false)
+ a = Account.create
a.errors.should have_key(:name)
end
describe "successful creation" do
let(:account) { Account.create(:name => "Adidas Corporation") }
- it "has a 15 character long id" do
- account.id.size.should == 15
+ it "has a 18 character long id" do
+ account.id.size.should == 18
end
- it 'is not active by default' do
- account.active.should_not be_true
+ it 'is not deleted by default' do
+ account.deleted.should_not be_true
end
it 'floats can be nil' do
@@ -38,9 +40,9 @@
end
end
describe "successful creation with on-offs" do
- let(:account) { Account.create(:name => "Adidas Corporation", :active => true, :annual_revenue => 4000.25) }
- it 'is active' do
- account.active.should be_true
+ let(:account) { Account.create(:name => "Adidas Corporation", :annual_revenue => 4000.25) }
+ it 'is not deleted' do
+ account.deleted.should_not be_true
end
it 'has 4000.25 in annual revenue' do
account.annual_revenue.should eql(4000.25)
View
76 spec/models/contact_spec.rb
@@ -1,3 +1,5 @@
+require 'spec/spec_helper'
+
describe "Finding a Contact" do
let(:valid_id) { DataMapper.repository(:salesforce) { Contact.gen.id } }
@@ -5,14 +7,14 @@
Contact.first(:id => valid_id).should_not be_nil
end
- it "has a 15 character long id" do
+ it "has a 18 character long id" do
#pending "testing serial types should be done elsewhere"
- Contact.first(:id => valid_id).id.size.should == 15
+ Contact.first(:id => valid_id).id.size.should == 18
end
- it "has a 15 character long account_id" do
+ it "has a 18 character long account_id" do
#pending "testing association ids as serial types should be done elsewhere"
- Contact.first(:id => valid_id).account_id.size.should == 15
+ Contact.first(:id => valid_id).account_id.size.should == 18
end
it "should get a single contact" do
@@ -53,20 +55,6 @@
end
end
- describe "when a unique property" do
- before(:each) do
- Contact.all(:irc_nick => 'c00ldud3').destroy
- end
-
- it "is invalid" do
- contact = Contact.gen(:irc_nick => 'c00ldud3')
- contact.should be_valid
-
- duplicate_irc_nick = Contact.gen(:irc_nick => 'c00ldud3')
- duplicate_irc_nick.should_not be_valid
- end
- end
-
describe "when the last name is missing" do
it "is invalid" do
contact = Contact.create(:first_name => 'Per', :email => "person@company.com")
@@ -96,27 +84,6 @@
end
end
- describe "when a unique property" do
- before(:each) do
- Contact.all(:irc_nick.like => 'c00ldud%').destroy
- end
- it "is invalid" do
- #pending "test duplicates on update elsewhere"
- contact = Contact.gen(:irc_nick => 'c00ldud3')
- contact.should be_valid
-
- conflicting_contact_after_update = Contact.gen(:irc_nick => 'c00ldud4')
- conflicting_contact_after_update.should be_valid
-
- lambda do
- contact.update(:irc_nick => 'c00ldud5')
- end.should_not change { contact.valid? }
- lambda do
- conflicting_contact_after_update.update(:irc_nick => 'c00ldud5')
- end.should change { conflicting_contact_after_update.valid? }
- end
- end
-
describe "when the last name is missing" do
it "is invalid" do
contact = Contact.create(:first_name => 'Per', :last_name => 'Son', :email => "person@company.com")
@@ -126,35 +93,4 @@
end
end
- describe "when updating a boolean field to false" do
- before(:each) do
- Contact.all(:first_name => 'OptOutEr').destroy
- end
- it "should update" do
- contact = Contact.gen(:first_name => 'OptOutEr', :has_opted_out_of_email => true)
-
- contact.update(:has_opted_out_of_email => false)
- Contact.get(contact.id).has_opted_out_of_email.should be_false
- end
- end
-
- describe "when updating a boolean field to true" do
- before(:each) do
- Contact.all(:first_name => 'OptOutEr').destroy
- end
- it "should update" do
- contact = Contact.gen(:first_name => 'OptOutEr', :has_opted_out_of_email => false)
-
- contact.update(:has_opted_out_of_email => true)
- Contact.get(contact.id).has_opted_out_of_email.should be_true
- end
- end
-
- describe "filtering on account_id and active" do
- it 'passes' do
- account = Account.first
- contact = Contact.create(:first_name => 'Per', :last_name => 'Son', :email => "person@company.com", :account_id => account.id, :active => true)
- Contact.all(:account_id => account.id, :active => true).should include(contact)
- end
- end
end
View
98 spec/models/event_spec.rb
@@ -0,0 +1,98 @@
+require 'spec/spec_helper'
+
+describe "Creating an Event" do
+
+ describe "when a unique property" do
+
+ before(:each) do
+ Event.all(:subject.like => 'Summer picnic%').destroy
+ end
+
+ it "is invalid" do
+ event = Event.gen(:subject => 'Summer picnic')
+ event.should be_valid
+
+ duplicate_subject = Event.gen(:subject => 'Summer picnic')
+ duplicate_subject.should_not be_valid
+ end
+
+ end
+
+end
+
+
+describe "Updating an Event" do
+
+ describe "when updating a boolean field to false" do
+
+ before(:each) do
+ Event.all(:subject => 'Boolean Update Test').destroy
+ end
+
+ it "should update to false" do
+ event = Event.gen(:subject => 'Boolean Update Test', :all_day_event => true)
+ event.update(:all_day_event => false, :activity_date_time => Time.now)
+ Event.get(event.id).all_day_event.should be_false
+ end
+
+ end
+
+
+ describe "when updating a boolean field to true" do
+ before(:each) do
+ Event.all(:subject => 'Boolean Update Test').destroy
+ end
+ it "should update to true" do
+ event = Event.gen(:subject => 'Boolean Update Test', :all_day_event => false)
+ Event.update(:all_day_event => true)
+ Event.get(event.id).all_day_event.should be_true
+ end
+ end
+
+
+ describe "when a unique property" do
+
+ before(:each) do
+ Event.all(:subject.like => 'Summer picnic%').destroy
+ end
+
+ it "is invalid" do
+ #pending "test duplicates on update elsewhere"
+ event = Event.gen(:subject => 'Summer picnic - bring umbrellas')
+ event.should be_valid
+
+ conflicting_event_after_update = Event.gen(:subject => 'Summer picnic - bring sunglasses')
+ conflicting_event_after_update.should be_valid
+
+ lambda do
+ event.update(:subject => 'Summer picnic - bring food')
+ end.should_not change { event.valid? }
+ lambda do
+ conflicting_event_after_update.update(:subject => 'Summer picnic - bring food')
+ end.should change { conflicting_event_after_update.valid? }
+ end
+
+ end
+
+
+ describe "filtering on string and boolean" do
+ before(:each) do
+ Event.all(:subject.like => 'Sack Race').destroy
+ end
+
+
+ it 'includes' do
+ account = Account.first
+ event = Event.gen(:subject => 'Sack Race', :all_day_event => true)
+ Event.all(:subject => 'Sack Race', :all_day_event => true).should include(event)
+ end
+
+ it 'excludes' do
+ account = Account.first
+ event = Event.gen(:subject => 'Sack Race', :all_day_event => true)
+ Event.all(:subject => 'Sack Race', :all_day_event => false).should_not include(event)
+ end
+
+ end
+
+end
View
55 spec/property/boolean_spec.rb
@@ -1,14 +1,57 @@
+require 'spec/spec_helper'
+
describe SalesforceAdapter::Property::Boolean do
- let(:active_account) { DataMapper.repository(:salesforce) { Account.gen(:active => true) } }
- let(:inactive_account) { DataMapper.repository(:salesforce) { Account.gen(:active => false) } }
+ let(:all_day_event) { DataMapper.repository(:salesforce) { Event.gen(:all_day_event => true) } }
+ let(:quick_event) { DataMapper.repository(:salesforce) { Event.gen(:all_day_event => false) } }
+
describe 'dumps and loads' do
- it 'true' do
- Account.first(:id => active_account.id).active.should == true
+
+ it 'should be true' do
+ Event.first(:id => all_day_event.id).all_day_event.should be_true
+ end
+
+ it 'should be false' do
+ Event.first(:id => quick_event.id).all_day_event.should be_false
+ end
+
+ end
+
+
+ describe 'after create' do
+
+ it 'should be true' do
+ all_day_event.all_day_event.should be_true
end
- it 'false' do
- Account.first(:id => inactive_account.id).active.should == false
+ it 'should be false' do
+ quick_event.all_day_event.should be_false
end
+
end
+
+
+ describe 'full cycle' do
+
+ it 'should be true all the way through' do
+ event = Event.gen(:all_day_event => true)
+ event.all_day_event.should be_true
+ event.save.should be_true
+ event.all_day_event.should be_true
+ event.reload.all_day_event.should be_true
+ Event.first(:id => event.id).all_day_event.should be_true
+ end
+
+
+ it 'should be false all the way through' do
+ event = Event.gen(:all_day_event => false)
+ event.all_day_event.should be_false
+ event.save.should be_true
+ event.all_day_event.should be_false
+ event.reload.all_day_event.should be_false
+ Event.first(:id => event.id).all_day_event.should be_false
+ end
+
+ end
+
end
View
7 spec/spec_helper.rb
@@ -5,10 +5,12 @@
$:.unshift root
require 'logger'
+Dir.mkdir(root + "/tmp") unless File.exist?(root + "/tmp")
::DataMapper.logger = Logger.new(root + "/tmp/test.log")
require 'spec/fixtures/account'
require 'spec/fixtures/contact'
+require 'spec/fixtures/event'
# Default config - needs to be overridden
sfconfig = {
@@ -32,6 +34,11 @@
api_dir = sfconfig["apidir"]
wsdl = sfconfig["path"]
+VALID_USERNAME = sfconfig["username"]
+VALID_PASSWORD = sfconfig["password"]
+
+raise "WSDL not found: #{wsdl}" unless File.exist?(wsdl)
+
FileUtils.rm_rf(api_dir)
FileUtils.mkdir_p(api_dir)
View
2 spec/sql_spec.rb
@@ -1,3 +1,5 @@
+require 'spec/spec_helper'
+
describe SalesforceAdapter::SQL do
describe "Operator" do
let(:account) { Account.gen(:number_of_employees => 10) }
Something went wrong with that request. Please try again.