Skip to content

Commit

Permalink
Add record type to object base (#6)
Browse files Browse the repository at this point in the history
* Add record type to object base

* Fix cache key uniqness issue
  • Loading branch information
vishalvijay committed Jun 29, 2017
1 parent d5bcff6 commit 0881f3f
Show file tree
Hide file tree
Showing 14 changed files with 276 additions and 14 deletions.
10 changes: 3 additions & 7 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -65,7 +61,7 @@ PLATFORMS

DEPENDENCIES
bundler (~> 1.15)
byebug (~> 0)
byebug (~> 9)
rake (~> 10.0)
rspec (~> 3.0)
salesforce-orm!
Expand Down
23 changes: 20 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -211,7 +229,6 @@ SampleObject.build({id: 'some id', field_one: 'Some value'})

- Default values
- Relationships
- Record type
- More data types
- Better aggregate methods

Expand Down
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
@@ -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-*
Expand Down
9 changes: 8 additions & 1 deletion lib/salesforce-orm/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions lib/salesforce-orm/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ class Base < StandardError; end
class CommonError < Base; end

class ObjectNotFound < Base; end

class RecordTypeNotFound < Base; end
end
end
8 changes: 8 additions & 0 deletions lib/salesforce-orm/object.rb
Original file line number Diff line number Diff line change
@@ -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
15 changes: 15 additions & 0 deletions lib/salesforce-orm/object/record_type.rb
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions lib/salesforce-orm/object_maker.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
require_relative 'record_type_manager'

module SalesforceOrm
module ObjectMaker

include RecordTypeManager

DEFAULT_FIELD_MAP = {
id: :Id,
created_at: :CreatedDate,
Expand Down
47 changes: 47 additions & 0 deletions lib/salesforce-orm/record_type_manager.rb
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion lib/salesforce-orm/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module SalesforceOrm
VERSION = '1.0.0'.freeze
VERSION = '1.1.0'.freeze
end
2 changes: 1 addition & 1 deletion salesforce-orm.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
35 changes: 35 additions & 0 deletions spec/object_base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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|
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
130 changes: 130 additions & 0 deletions spec/record_type_manager_spec.rb
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 0881f3f

Please sign in to comment.