active_force 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ require 'active_force/sobject'
2
+
3
+ class <%= @class_name %> < ActiveForce::SObject
4
+ <% attributes.each do |attribute| -%>
5
+ <%= attribute_line attribute %>
6
+ <% end -%>
7
+ end
@@ -2,18 +2,15 @@ require 'spec_helper'
2
2
  require 'active_force/active_query'
3
3
 
4
4
  describe ActiveForce::ActiveQuery do
5
- let(:sobject){
6
- sobject = double("sobject")
7
- allow(sobject).to receive(:table_name).and_return "table_name"
8
- allow(sobject).to receive(:fields).and_return []
9
- allow(sobject).to receive(:mappings).and_return({field: "Field__c"})
10
- sobject
11
- }
12
-
13
- let(:client){
14
- double("client")
15
- }
16
-
5
+ let(:sobject) do
6
+ double("sobject", {
7
+ table_name: "table_name",
8
+ fields: [],
9
+ mappings: mappings
10
+ })
11
+ end
12
+ let(:mappings){ { field: "Field__c", other_field: "Other_Field" } }
13
+ let(:client){ double("client") }
17
14
  let(:active_query){ ActiveForce::ActiveQuery.new(sobject) }
18
15
 
19
16
  before do
@@ -37,6 +34,13 @@ describe ActiveForce::ActiveQuery do
37
34
  end
38
35
  end
39
36
 
37
+ describe "select only some field using mappings" do
38
+ it "should return a query only with selected field" do
39
+ active_query.select(:field)
40
+ expect(active_query.to_s).to eq("SELECT Field__c FROM table_name")
41
+ end
42
+ end
43
+
40
44
  describe "condition mapping" do
41
45
  it "maps conditions for a .where" do
42
46
  active_query.where(field: 123)
@@ -47,6 +51,69 @@ describe ActiveForce::ActiveQuery do
47
51
  active_query.where field: "hello"
48
52
  expect(active_query.to_s).to end_with("Field__c = 'hello'")
49
53
  end
54
+
55
+ it "puts NULL when a field is set as nil" do
56
+ active_query.where field: nil
57
+ expect(active_query.to_s).to end_with("Field__c = NULL")
58
+ end
59
+
60
+ describe 'bind parameters' do
61
+ let(:mappings) do
62
+ super().merge({
63
+ other_field: 'Other_Field__c',
64
+ name: 'Name'
65
+ })
66
+ end
67
+
68
+ it 'accepts bind parameters' do
69
+ active_query.where('Field__c = ?', 123)
70
+ expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE Field__c = 123")
71
+ end
72
+
73
+ it 'accepts nil bind parameters' do
74
+ active_query.where('Field__c = ?', nil)
75
+ expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE Field__c = NULL")
76
+ end
77
+
78
+ it 'accepts multiple bind parameters' do
79
+ active_query.where('Field__c = ? AND Other_Field__c = ? AND Name = ?', 123, 321, 'Bob')
80
+ expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE Field__c = 123 AND Other_Field__c = 321 AND Name = 'Bob'")
81
+ end
82
+
83
+ it 'complains when there given an incorrect number of bind parameters' do
84
+ expect{
85
+ active_query.where('Field__c = ? AND Other_Field__c = ? AND Name = ?', 123, 321)
86
+ }.to raise_error(ActiveForce::PreparedStatementInvalid, 'wrong number of bind variables (2 for 3)')
87
+ end
88
+
89
+ context 'named bind parameters' do
90
+ it 'accepts bind parameters' do
91
+ active_query.where('Field__c = :field', field: 123)
92
+ expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE Field__c = 123")
93
+ end
94
+
95
+ it 'accepts nil bind parameters' do
96
+ active_query.where('Field__c = :field', field: nil)
97
+ expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE Field__c = NULL")
98
+ end
99
+
100
+ it 'accepts multiple bind parameters' do
101
+ active_query.where('Field__c = :field AND Other_Field__c = :other_field AND Name = :name', field: 123, other_field: 321, name: 'Bob')
102
+ expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE Field__c = 123 AND Other_Field__c = 321 AND Name = 'Bob'")
103
+ end
104
+
105
+ it 'accepts multiple bind parameters orderless' do
106
+ active_query.where('Field__c = :field AND Other_Field__c = :other_field AND Name = :name', name: 'Bob', other_field: 321, field: 123)
107
+ expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE Field__c = 123 AND Other_Field__c = 321 AND Name = 'Bob'")
108
+ end
109
+
110
+ it 'complains when there given an incorrect number of bind parameters' do
111
+ expect{
112
+ active_query.where('Field__c = :field AND Other_Field__c = :other_field AND Name = :name', field: 123, other_field: 321)
113
+ }.to raise_error(ActiveForce::PreparedStatementInvalid, 'missing value for :name in Field__c = :field AND Other_Field__c = :other_field AND Name = :name')
114
+ end
115
+ end
116
+ end
50
117
  end
51
118
 
52
119
  describe "#find_by" do
@@ -4,20 +4,15 @@ require 'active_force/association'
4
4
  describe ActiveForce::SObject do
5
5
 
6
6
  let :post do
7
- post = Post.new
8
- allow(post).to receive(:id).and_return "1"
9
- post
7
+ Post.new(id: "1")
10
8
  end
11
9
 
12
10
  let :comment do
13
- comment = Comment.new
14
- allow(comment).to receive(:id).and_return "1"
15
- allow(comment).to receive(:post_id).and_return "1"
16
- comment
11
+ Comment.new(id: "1", post_id: "1")
17
12
  end
18
13
 
19
14
  let :client do
20
- double("sfdc_client")
15
+ double("sfdc_client", query: [Restforce::Mash.new(id: 1)])
21
16
  end
22
17
 
23
18
  before do
@@ -34,7 +29,6 @@ describe ActiveForce::SObject do
34
29
  end
35
30
 
36
31
  describe "has_many_query" do
37
-
38
32
  before do
39
33
  class Post < ActiveForce::SObject
40
34
  has_many :comments
@@ -49,13 +43,46 @@ describe ActiveForce::SObject do
49
43
  expect(post.comments).to be_a ActiveForce::ActiveQuery
50
44
  end
51
45
 
46
+ it 'makes only one API call to fetch the associated object' do
47
+ expect(client).to receive(:query).once
48
+ post.comments.to_a
49
+ post.comments.to_a
50
+ end
51
+
52
52
  describe 'to_s' do
53
- it "should retrun a SOQL statment" do
53
+ it "should return a SOQL statment" do
54
54
  soql = "SELECT Id, PostId FROM Comment__c WHERE PostId = '1'"
55
- expect(post.comments.to_s).to eq soql
55
+ expect(post.comments.to_s).to eq soql
56
56
  end
57
57
  end
58
58
 
59
+ context 'when the SObject is namespaced' do
60
+ let(:account){ Foo::Account.new(id: '1') }
61
+
62
+ before do
63
+ module Foo
64
+ class Opportunity < ActiveForce::SObject
65
+ field :account_id, from: 'AccountId'
66
+ end
67
+
68
+ class Account < ActiveForce::SObject
69
+ has_many :opportunities, model: Foo::Opportunity
70
+ end
71
+ end
72
+ end
73
+
74
+ it 'correctly infers the foreign key and forms the correct query' do
75
+ soql = "SELECT Id, AccountId FROM Opportunity WHERE AccountId = '1'"
76
+ expect(account.opportunities.to_s).to eq soql
77
+ end
78
+
79
+ it 'uses an explicit foreign key if it is supplied' do
80
+ Foo::Opportunity.field :partner_account_id, from: 'Partner_Account_Id__c'
81
+ Foo::Account.has_many :opportunities, foreign_key: :partner_account_id, model: Foo::Opportunity
82
+ soql = "SELECT Id, AccountId, Partner_Account_Id__c FROM Opportunity WHERE Partner_Account_Id__c = '1'"
83
+ expect(account.opportunities.to_s).to eq soql
84
+ end
85
+ end
59
86
  end
60
87
 
61
88
  describe 'has_many(options)' do
@@ -70,8 +97,8 @@ describe ActiveForce::SObject do
70
97
  end
71
98
 
72
99
  it 'should allow to change the foreign key' do
73
- Post.has_many :comments, { foreign_key: :post }
74
- Comment.field :post, from: 'PostId'
100
+ Post.has_many :comments, { foreign_key: :poster }
101
+ Comment.field :poster, from: 'PostId'
75
102
  soql = "SELECT Id, PostId FROM Comment__c WHERE PostId = '1'"
76
103
  expect(post.comments.to_s).to eq soql
77
104
  end
@@ -90,13 +117,11 @@ describe ActiveForce::SObject do
90
117
  end
91
118
 
92
119
  describe "belongs_to" do
93
-
94
120
  before do
95
- allow(client).to receive(:query).and_return [Restforce::Mash.new(id: 1)]
121
+ Comment.belongs_to :post
96
122
  end
97
123
 
98
124
  it "should get the resource it belongs to" do
99
- Comment.belongs_to :post
100
125
  expect(comment.post).to be_instance_of(Post)
101
126
  end
102
127
 
@@ -110,5 +135,58 @@ describe ActiveForce::SObject do
110
135
  comment.post
111
136
  end
112
137
 
138
+ it 'makes only one API call to fetch the associated object' do
139
+ expect(client).to receive(:query).once
140
+ comment.post
141
+ comment.post
142
+ end
143
+
144
+ it 'accepts assignment of an existing object as an association' do
145
+ expect(client).to_not receive(:query)
146
+ other_post = Post.new(id: "2")
147
+ comment.post = other_post
148
+ expect(comment.post_id).to eq other_post.id
149
+ expect(comment.post).to eq other_post
150
+ end
151
+
152
+ context 'when the SObject is namespaced' do
153
+ let(:attachment){ Foo::Attachment.new(id: '1', lead_id: '2') }
154
+ before do
155
+ module Foo
156
+ class Lead < ActiveForce::SObject; end
157
+
158
+ class Attachment < ActiveForce::SObject
159
+ field :lead_id, from: 'Lead_Id__c'
160
+ belongs_to :lead, model: Foo::Lead
161
+ end
162
+ end
163
+ end
164
+
165
+ it 'generates the correct query' do
166
+ expect(client).to receive(:query).with("SELECT Id FROM Lead WHERE Id = '2' LIMIT 1")
167
+ attachment.lead
168
+ end
169
+
170
+ it 'instantiates the correct object' do
171
+ expect(attachment.lead).to be_instance_of(Foo::Lead)
172
+ end
173
+
174
+ context 'when given a foreign key' do
175
+ let(:attachment){ Foo::Attachment.new(id: '1', fancy_lead_id: '2') }
176
+ before do
177
+ module Foo
178
+ class Attachment < ActiveForce::SObject
179
+ field :fancy_lead_id, from: 'LeadId'
180
+ belongs_to :lead, model: Foo::Lead, foreign_key: :fancy_lead_id
181
+ end
182
+ end
183
+ end
184
+
185
+ it 'generates the correct query' do
186
+ expect(client).to receive(:query).with("SELECT Id FROM Lead WHERE Id = '2' LIMIT 1")
187
+ attachment.lead
188
+ end
189
+ end
190
+ end
113
191
  end
114
192
  end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ require 'active_force/sobject'
3
+
4
+ describe ActiveForce::SObject do
5
+ let(:client) { double 'Client', create!: 'id' }
6
+
7
+ before do
8
+ allow(ActiveForce::SObject).to receive(:sfdc_client).and_return client
9
+ end
10
+
11
+ describe "save" do
12
+
13
+ it 'call action callback when save a record' do
14
+ class Whizbanged < ActiveForce::SObject
15
+
16
+ field :updated_from
17
+ field :dirty_attribute
18
+
19
+ before_save :set_as_updated_from_rails
20
+ after_save :mark_dirty
21
+
22
+ private
23
+
24
+ def set_as_updated_from_rails
25
+ self.updated_from = 'Rails'
26
+ end
27
+
28
+ def mark_dirty
29
+ self.dirty_attribute = true
30
+ end
31
+
32
+ end
33
+
34
+ whizbanged = Whizbanged.new
35
+ whizbanged.save
36
+ expect(whizbanged.updated_from).to eq 'Rails'
37
+ expect(whizbanged.dirty_attribute).to eq true
38
+ expect(whizbanged.changed.include? 'dirty_attribute').to eq true
39
+ expect(whizbanged.changed.include? 'updated_from').to eq false
40
+ end
41
+ end
42
+ end
@@ -11,6 +11,16 @@ describe ActiveForce::Query do
11
11
  after do
12
12
  end
13
13
 
14
+ describe '.select' do
15
+ it 'use column sent on the select method' do
16
+ expect(@query.select('name').all.to_s).to eq "SELECT name FROM table_name"
17
+ end
18
+
19
+ it 'use columns sent on the select method' do
20
+ expect(@query.select(['id','name']).all.to_s).to eq "SELECT id, name FROM table_name"
21
+ end
22
+ end
23
+
14
24
  describe ".all" do
15
25
  it "table should return table name" do
16
26
  expect(@query.all.table).to eq(@query.table)
@@ -25,13 +25,24 @@ describe ActiveForce::SObject do
25
25
  expect(EnforcedTableName.table_name).to eq('Forced__c')
26
26
  end
27
27
 
28
- it "doesn't include a namespace" do
29
- module Foo
30
- class Bar < ActiveForce::SObject
28
+ context 'with a namespace' do
29
+ it "the namespace is not included" do
30
+ module Foo
31
+ class Bar < ActiveForce::SObject
32
+ end
31
33
  end
34
+
35
+ expect(Foo::Bar.table_name).to eq('Bar__c')
32
36
  end
33
37
 
34
- expect(Foo::Bar.table_name).to eq('Bar__c')
38
+ it 'standard types are inferred correctly' do
39
+ module Foo
40
+ class Account < ActiveForce::SObject
41
+ end
42
+ end
43
+
44
+ expect(Foo::Account.table_name).to eq('Account')
45
+ end
35
46
  end
36
47
  end
37
48
  end
@@ -55,16 +55,46 @@ describe ActiveForce::SObject do
55
55
  expect(Quota.mappings[:id]).to eq 'Bar_Id__c'
56
56
  end
57
57
  end
58
+
59
+ context 'as: :multi_picklist' do
60
+ before do
61
+ class IceCream < ActiveForce::SObject
62
+ field :flavors, as: :multi_picklist
63
+ end
64
+ sundae.flavors = %w(chocolate vanilla strawberry)
65
+ end
66
+
67
+ context 'on create' do
68
+ let(:sundae) { IceCream.new }
69
+ it 'formats the picklist values' do
70
+ expect(client).to receive(:create!).with('IceCream__c', {'Flavors__c' => 'chocolate;vanilla;strawberry'})
71
+ sundae.save
72
+ end
73
+ end
74
+
75
+ context 'on update' do
76
+ let(:sundae) { IceCream.new(id: '1') }
77
+ it 'formats the picklist values' do
78
+ expect(client).to receive(:update!).with('IceCream__c', {'Flavors__c' => 'chocolate;vanilla;strawberry', 'Id' => '1'})
79
+ sundae.save
80
+ end
81
+ end
82
+
83
+ end
58
84
  end
59
85
 
60
86
  describe '#update' do
61
87
 
62
88
  subject do
63
- Whizbang.new
89
+ Whizbang.new(id: '1')
64
90
  end
65
91
 
66
92
  before do
67
- expect(client).to receive(:update!).and_return('id')
93
+ expected_args = [
94
+ Whizbang.table_name,
95
+ {'Text_Label' => 'some text', 'Id' => '1'}
96
+ ]
97
+ expect(client).to receive(:update!).with(*expected_args).and_return('id')
68
98
  end
69
99
 
70
100
  it 'delegates to the Client with create!' do
@@ -97,7 +127,7 @@ describe ActiveForce::SObject do
97
127
  describe 'self.create' do
98
128
 
99
129
  before do
100
- expect(client).to receive(:create!).and_return('id')
130
+ expect(client).to receive(:create!).with(Whizbang.table_name, 'Text_Label' => 'some text').and_return('id')
101
131
  end
102
132
 
103
133
  it 'should create a new instance' do
@@ -126,4 +156,43 @@ describe ActiveForce::SObject do
126
156
  Whizbang.find_by id: 123, text: "foo"
127
157
  end
128
158
  end
159
+
160
+ describe '#reload' do
161
+ let(:client) do
162
+ double("sfdc_client", query: [Restforce::Mash.new(Id: 1, Name: 'Jeff')])
163
+ end
164
+ let(:quota){ Quota.new(id: '1') }
165
+ let(:territory){ Territory.new(id: '1', quota_id: '1') }
166
+
167
+ before do
168
+ Territory.belongs_to :quota, model: Quota
169
+ Territory.field :quota_id, from: 'Quota_Id'
170
+ allow(ActiveForce::SObject).to receive(:sfdc_client).and_return client
171
+ end
172
+
173
+ it 'clears cached associations' do
174
+ soql = "SELECT Id, Bar_Id__c FROM Quota__c WHERE Id = '1' LIMIT 1"
175
+ expect(client).to receive(:query).twice.with soql
176
+ allow(Territory).to receive(:find){ territory }
177
+ territory.quota
178
+ territory.quota
179
+ territory.reload
180
+ territory.quota
181
+ end
182
+
183
+ it "refreshes the object's attributes" do
184
+ Territory.field :name, from: 'Name'
185
+ territory.name = 'Walter'
186
+ expect(territory.name).to eq 'Walter'
187
+ territory.reload
188
+ expect(territory.name).to eq 'Jeff'
189
+ expect(territory.changed_attributes).to be_empty
190
+ end
191
+
192
+ it 'returns the same object' do
193
+ allow(Territory).to receive(:find){ Territory.new }
194
+ expected = territory
195
+ expect(territory.reload).to eql expected
196
+ end
197
+ end
129
198
  end