diff --git a/Gemfile.lock b/Gemfile.lock index 5733c5a..8c5d52d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - salesforce-orm (1.0.0) + salesforce-orm (1.1.0) activerecord (~> 3) activerecord-nulldb-adapter (~> 0) restforce (~> 2.5) @@ -24,11 +24,7 @@ GEM multi_json (~> 1.0) arel (3.0.3) builder (3.0.4) - byebug (0.0.1) - columnize (>= 0.3.1) - debugger-linecache (~> 1.2.0) - columnize (0.9.0) - debugger-linecache (1.2.0) + byebug (9.0.5) diff-lcs (1.3) faraday (0.12.1) multipart-post (>= 1.2, < 3) @@ -65,7 +61,7 @@ PLATFORMS DEPENDENCIES bundler (~> 1.15) - byebug (~> 0) + byebug (~> 9) rake (~> 10.0) rspec (~> 3.0) salesforce-orm! diff --git a/README.md b/README.md index ce8851f..3c8d08b 100644 --- a/README.md +++ b/README.md @@ -111,14 +111,32 @@ If you wanna change the data type of some fields ``` class SampleObject < SalesforceOrm::ObjectBase self.data_type_map = { - created_at: :datetime, - updated_at: :datetime + field_one: :datetime, + field_two: :integer } end ``` **NOTE: It's mandatory to add data type map for boolean fields** +### record_type + +By default there is no record type configured for any object + +To specify a record type, + +``` +class SampleObject < SalesforceOrm::ObjectBase + self.record_type = 'Xyz' # DeveloperName in RecordType object +end +``` + +All the queries and `create!` method will automatically use record type + +First time use the object, we make a call to Salesforce and find the record type by it's `DeveloperName`. This will be cached in memory. + +With Rails in except in development or test env, we take the advantage of `Rails.cache` + ### Methods Methods are similar to ActiveRecord::Base @@ -211,7 +229,6 @@ SampleObject.build({id: 'some id', field_one: 'Some value'}) - Default values - Relationships -- Record type - More data types - Better aggregate methods diff --git a/build.sh b/build.sh index 3eaecc0..1258f9f 100644 --- a/build.sh +++ b/build.sh @@ -1,4 +1,4 @@ -gem uninstall -a salesforce-orm-* +gem uninstall -a salesforce-orm rm salesforce-orm-* gem build salesforce-orm.gemspec gem install salesforce-orm-* diff --git a/lib/salesforce-orm/base.rb b/lib/salesforce-orm/base.rb index 0cae966..0a91920 100755 --- a/lib/salesforce-orm/base.rb +++ b/lib/salesforce-orm/base.rb @@ -19,12 +19,19 @@ def initialize(klass) @klass = klass @client = RestforceClient.instance @builder = QueryBuilder.select(klass.field_map.keys) + where(RecordTypeManager::FIELD_NAME => klass.record_type_id) if klass.record_type_id end # create! doesn't return the SalesForce object back # It will return only the object id def create!(attributes) - client.create!(klass.object_name, map_to_keys(attributes)) + new_attributes = map_to_keys(attributes) + + new_attributes = new_attributes.merge( + RecordTypeManager::FIELD_NAME => klass.record_type_id + ) if klass.record_type_id + + client.create!(klass.object_name, new_attributes) end # Transaction not guaranteed diff --git a/lib/salesforce-orm/error.rb b/lib/salesforce-orm/error.rb index 2077b75..fb67d02 100755 --- a/lib/salesforce-orm/error.rb +++ b/lib/salesforce-orm/error.rb @@ -7,5 +7,7 @@ class Base < StandardError; end class CommonError < Base; end class ObjectNotFound < Base; end + + class RecordTypeNotFound < Base; end end end diff --git a/lib/salesforce-orm/object.rb b/lib/salesforce-orm/object.rb new file mode 100644 index 0000000..d118abd --- /dev/null +++ b/lib/salesforce-orm/object.rb @@ -0,0 +1,8 @@ +Dir[File.expand_path('object/*.rb', File.dirname(__FILE__))].each do |file| + require file +end + +module SalesforceOrm + module Object + end +end diff --git a/lib/salesforce-orm/object/record_type.rb b/lib/salesforce-orm/object/record_type.rb new file mode 100644 index 0000000..f1e5137 --- /dev/null +++ b/lib/salesforce-orm/object/record_type.rb @@ -0,0 +1,15 @@ +require_relative '../object_base' + +module SalesforceOrm + module Object + class RecordType < ObjectBase + + self.field_map = { + name: :Name, + sobject_type: :SobjectType, + developer_name: :DeveloperName, + } + + end + end +end diff --git a/lib/salesforce-orm/object_maker.rb b/lib/salesforce-orm/object_maker.rb index 7613e87..233a8e7 100755 --- a/lib/salesforce-orm/object_maker.rb +++ b/lib/salesforce-orm/object_maker.rb @@ -1,6 +1,10 @@ +require_relative 'record_type_manager' + module SalesforceOrm module ObjectMaker + include RecordTypeManager + DEFAULT_FIELD_MAP = { id: :Id, created_at: :CreatedDate, diff --git a/lib/salesforce-orm/record_type_manager.rb b/lib/salesforce-orm/record_type_manager.rb new file mode 100644 index 0000000..e8c4206 --- /dev/null +++ b/lib/salesforce-orm/record_type_manager.rb @@ -0,0 +1,47 @@ +module SalesforceOrm + module RecordTypeManager + + FIELD_NAME = :RecordTypeId + + def record_type=(new_record_type) + @record_type = new_record_type + end + + def record_type + @record_type + end + + def record_type_id + return nil unless record_type + return @record_type_id if @record_type_id + + record_type_sobject = if defined?(Rails) + if Rails.env.test? + Object::RecordType.build(id: 'fake_record_type') + elsif !Rails.env.development? + Rails.cache.fetch(record_type_cache_key) do + fetch_record_type + end + else + fetch_record_type + end + else + fetch_record_type + end + + raise Error::RecordTypeNotFound unless record_type_sobject + + @record_type_id = record_type_sobject.id + end + + private + + def fetch_record_type + Object::RecordType.where(developer_name: record_type).first + end + + def record_type_cache_key + ['RecordTypeManager', object_name, record_type].join('/') + end + end +end diff --git a/lib/salesforce-orm/version.rb b/lib/salesforce-orm/version.rb index 1a00ee3..b88d7d5 100644 --- a/lib/salesforce-orm/version.rb +++ b/lib/salesforce-orm/version.rb @@ -1,3 +1,3 @@ module SalesforceOrm - VERSION = '1.0.0'.freeze + VERSION = '1.1.0'.freeze end diff --git a/salesforce-orm.gemspec b/salesforce-orm.gemspec index ea2449b..c88b53a 100644 --- a/salesforce-orm.gemspec +++ b/salesforce-orm.gemspec @@ -24,7 +24,7 @@ Gem::Specification.new do |s| s.add_dependency 'activerecord-nulldb-adapter', '~> 0' s.add_dependency 'restforce', '~> 2.5' - s.add_development_dependency 'byebug', '~> 0' + s.add_development_dependency 'byebug', '~> 9' s.add_development_dependency 'rspec', '~> 3.0' s.add_development_dependency 'bundler', '~> 1.15' s.add_development_dependency 'rake', '~> 10.0' diff --git a/spec/object_base_spec.rb b/spec/object_base_spec.rb index a86b199..77cd087 100644 --- a/spec/object_base_spec.rb +++ b/spec/object_base_spec.rb @@ -57,6 +57,17 @@ def assign_field_map(new_field_map = nil) SampleObject.data_type_map = SalesforceOrm::ObjectMaker::DEFAULT_DATA_TYPE_MAP end + it 'should allow to use record type' do + expect(SampleObject.record_type).to be_nil + + record_type = 'Xyz' + SampleObject.record_type = record_type + + expect(SampleObject.record_type).to eq(record_type) + + SampleObject.record_type = nil + end + describe 'create!' do it 'should call create! method of restforce' do assign_field_map do |field_map| @@ -67,6 +78,19 @@ def assign_field_map(new_field_map = nil) SampleObject.create!({field1: :yo}) end end + + it 'should handle record type' do + record_type_id = 'yo' + + expect(SampleObject).to receive(:record_type_id).and_return(record_type_id).exactly(4).times + + + expect(SalesforceOrm::RestforceClient.instance).to receive(:create!).with( + SampleObject.object_name, + SalesforceOrm::RecordTypeManager::FIELD_NAME => record_type_id + ) + SampleObject.create!({}) + end end describe 'update_all!' do @@ -131,6 +155,17 @@ def assign_field_map(new_field_map = nil) soql = SampleObject.where(yo: 3, yoyo: 'Uiew').to_soql expect(soql).to eq('SELECT Id, CreatedDate, LastModifiedDate FROM SampleObject WHERE yo = 3 AND yoyo = \'Uiew\'') end + + it 'should handle record type' do + expect(SampleObject.scoped.to_soql).to eq('SELECT Id, CreatedDate, LastModifiedDate FROM SampleObject') + + record_type_id = 'yo' + + expect(SampleObject).to receive(:record_type_id).and_return(record_type_id).twice + expect(SampleObject.scoped.to_soql).to eq( + "SELECT Id, CreatedDate, LastModifiedDate FROM SampleObject WHERE RecordTypeId = '#{record_type_id}'" + ) + end end describe 'select' do diff --git a/spec/record_type_manager_spec.rb b/spec/record_type_manager_spec.rb new file mode 100644 index 0000000..48bf5d6 --- /dev/null +++ b/spec/record_type_manager_spec.rb @@ -0,0 +1,130 @@ +require 'spec_helper' +require_relative 'fixtures/sample_object' + +RSpec.describe SalesforceOrm::RecordTypeManager do + + it 'should have a constant call FIELD_NAME' do + expect(SalesforceOrm::RecordTypeManager::FIELD_NAME).to eq(:RecordTypeId) + end + + describe 'record_type_id' do + + let(:klass) do + Class.new SampleObject + end + + before(:each) do + klass.record_type = :yo + end + + describe 'Ruby ENV' do + + it 'should give nil record_type_id if there is not recordn type set' do + klass.record_type = nil + expect(klass.record_type_id).to be_nil + end + + + it 'should call fetch_record_type when first time' do + id = 'bhla' + expect(SampleObject).to receive(:fetch_record_type).and_return( + SalesforceOrm::Object::RecordType.build({ + id: id + }) + ) + expect(klass.record_type_id).to eq(id) + end + + it 'should not call fetch_record_type if already fetched' do + id = 'bhla' + expect(klass).to receive(:fetch_record_type).and_return( + SalesforceOrm::Object::RecordType.build({ + id: id + }) + ) + expect(klass.record_type_id).to eq(id) + + expect(klass).not_to receive(:fetch_record_type) + + expect(klass.record_type_id).to eq(id) + end + end + + + describe 'Rails ENV' do + + before(:all) do + class TestEnv + + def env=(env) + @env = env + end + + def method_missing(method_name, *args, &block) + method_name[0..-2] == @env + end + end + + class TestCache + + def self.fetch(*args) + yield + end + + end + + class ::Rails + + class << self + def env + @env ||= TestEnv.new + end + + def env_name=(env_name) + env.env = env_name + end + + def cache + TestCache + end + end + end + end + + it 'should return fake_record_type for test env' do + Rails.env_name = 'test' + + expect(klass.record_type_id).to eq('fake_record_type') + end + + it 'should call fetch_record_type in development env' do + Rails.env_name = 'development' + + id = 'bhla' + expect(klass).to receive(:fetch_record_type).and_return( + SalesforceOrm::Object::RecordType.build({ + id: id + }) + ) + expect(klass.record_type_id).to eq(id) + end + + it 'should call Rails.cache evns expcept test and development' do + Rails.env_name = 'production' + + klass.object_name = 'SampleObject' + + expect(Rails).to receive(:cache).and_return(TestCache) + + id = 'bhla' + expect(klass).to receive(:fetch_record_type).and_return( + SalesforceOrm::Object::RecordType.build({ + id: id + }) + ) + + expect(klass.record_type_id).to eq('bhla') + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a8fc24c..3e1e16d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,6 @@ require 'bundler/setup' require 'salesforce-orm' +require 'byebug' RSpec.configure do |config| # Enable flags like --only-failures and --next-failure