openstax_active_force 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.mailmap +3 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +3 -0
  6. data/CHANGELOG.md +98 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +174 -0
  10. data/Rakefile +6 -0
  11. data/active_force.gemspec +30 -0
  12. data/lib/active_attr/dirty.rb +33 -0
  13. data/lib/active_force/active_query.rb +155 -0
  14. data/lib/active_force/association/association.rb +50 -0
  15. data/lib/active_force/association/belongs_to_association.rb +26 -0
  16. data/lib/active_force/association/eager_load_projection_builder.rb +60 -0
  17. data/lib/active_force/association/has_many_association.rb +33 -0
  18. data/lib/active_force/association/relation_model_builder.rb +70 -0
  19. data/lib/active_force/association.rb +28 -0
  20. data/lib/active_force/attribute.rb +30 -0
  21. data/lib/active_force/mapping.rb +78 -0
  22. data/lib/active_force/query.rb +110 -0
  23. data/lib/active_force/sobject.rb +210 -0
  24. data/lib/active_force/standard_types.rb +357 -0
  25. data/lib/active_force/table.rb +37 -0
  26. data/lib/active_force/version.rb +3 -0
  27. data/lib/active_force.rb +13 -0
  28. data/lib/generators/active_force/model/USAGE +8 -0
  29. data/lib/generators/active_force/model/model_generator.rb +62 -0
  30. data/lib/generators/active_force/model/templates/model.rb.erb +5 -0
  31. data/spec/active_force/active_query_spec.rb +178 -0
  32. data/spec/active_force/association/relation_model_builder_spec.rb +62 -0
  33. data/spec/active_force/association_spec.rb +157 -0
  34. data/spec/active_force/attribute_spec.rb +27 -0
  35. data/spec/active_force/callbacks_spec.rb +20 -0
  36. data/spec/active_force/mapping_spec.rb +18 -0
  37. data/spec/active_force/query_spec.rb +126 -0
  38. data/spec/active_force/sobject/includes_spec.rb +290 -0
  39. data/spec/active_force/sobject/table_name_spec.rb +27 -0
  40. data/spec/active_force/sobject_spec.rb +398 -0
  41. data/spec/active_force/table_spec.rb +25 -0
  42. data/spec/active_force_spec.rb +7 -0
  43. data/spec/fixtures/sobject/single_sobject_hash.yml +26 -0
  44. data/spec/spec_helper.rb +16 -0
  45. data/spec/support/fixture_helpers.rb +45 -0
  46. data/spec/support/restforce_factories.rb +9 -0
  47. data/spec/support/sobjects.rb +97 -0
  48. data/spec/support/whizbang.rb +30 -0
  49. metadata +196 -0
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ module ActiveForce
4
+ module Association
5
+ describe RelationModelBuilder do
6
+ let(:instance){ described_class.new association, value }
7
+
8
+ describe '#build_relation_model' do
9
+ context 'has_many' do
10
+ let(:association){ HasManyAssociation.new Post, :comments }
11
+
12
+ context 'with values' do
13
+ let(:value) do
14
+ build_restforce_collection([
15
+ Restforce::SObject.new({'Id' => '213', 'PostId' => '123'}),
16
+ Restforce::SObject.new({'Id' => '214', 'PostId' => '123'})
17
+ ])
18
+ end
19
+
20
+ it 'returns an array of Comments' do
21
+ comments = instance.build_relation_model
22
+ expect(comments).to be_a Array
23
+ expect(comments.all?{ |c| c.is_a? Comment }).to be true
24
+ end
25
+ end
26
+
27
+ context 'without values' do
28
+ let(:value){ nil }
29
+
30
+ it 'returns an empty array' do
31
+ comments = instance.build_relation_model
32
+ expect(comments).to be_a Array
33
+ expect(comments).to be_empty
34
+ end
35
+ end
36
+ end
37
+
38
+ context 'belongs_to' do
39
+ let(:association){ BelongsToAssociation.new(Comment, :post) }
40
+
41
+ context 'with a value' do
42
+ let(:value) do
43
+ build_restforce_sobject 'Id' => '213'
44
+ end
45
+
46
+ it 'returns a post' do
47
+ expect(instance.build_relation_model).to be_a Post
48
+ end
49
+ end
50
+
51
+ context 'without a value' do
52
+ let(:value){ nil }
53
+
54
+ it 'returns nil' do
55
+ expect(instance.build_relation_model).to be_nil
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,157 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveForce::SObject do
4
+ let :post do
5
+ Post.new(id: "1", title: 'Ham')
6
+ end
7
+
8
+ let :comment do
9
+ Comment.new(id: "1", post_id: "1")
10
+ end
11
+
12
+ let :client do
13
+ double("sfdc_client", query: [Restforce::Mash.new("Id" => 1)])
14
+ end
15
+
16
+ before do
17
+ ActiveForce.sfdc_client = client
18
+ end
19
+
20
+ describe "has_many_query" do
21
+ it "should respond to relation method" do
22
+ expect(post).to respond_to(:comments)
23
+ end
24
+
25
+ it "should return a ActiveQuery object" do
26
+ expect(post.comments).to be_a ActiveForce::ActiveQuery
27
+ end
28
+
29
+ it 'makes only one API call to fetch the associated object' do
30
+ expect(client).to receive(:query).once
31
+ post.comments.to_a
32
+ post.comments.to_a
33
+ end
34
+
35
+ describe 'to_s' do
36
+ it "should return a SOQL statment" do
37
+ soql = "SELECT Id, PostId, PosterId__c, FancyPostId, Body__c FROM Comment__c WHERE (PostId = '1')"
38
+ expect(post.comments.to_s).to eq soql
39
+ end
40
+ end
41
+
42
+ context 'when the SObject is namespaced' do
43
+ let(:account){ Foo::Account.new(id: '1') }
44
+
45
+ it 'correctly infers the foreign key and forms the correct query' do
46
+ soql = "SELECT Id, AccountId, Partner_Account_Id__c FROM Opportunity WHERE (AccountId = '1')"
47
+ expect(account.opportunities.to_s).to eq soql
48
+ end
49
+
50
+ it 'uses an explicit foreign key if it is supplied' do
51
+ soql = "SELECT Id, AccountId, Partner_Account_Id__c FROM Opportunity WHERE (Partner_Account_Id__c = '1')"
52
+ expect(account.partner_opportunities.to_s).to eq soql
53
+ end
54
+ end
55
+ end
56
+
57
+ describe 'has_many(options)' do
58
+ it 'should allow to send a different query table name' do
59
+ soql = "SELECT Id, PostId, PosterId__c, FancyPostId, Body__c FROM Comment__c WHERE (PostId = '1')"
60
+ expect(post.ugly_comments.to_s).to eq soql
61
+ end
62
+
63
+ it 'should allow to change the foreign key' do
64
+ soql = "SELECT Id, PostId, PosterId__c, FancyPostId, Body__c FROM Comment__c WHERE (PosterId__c = '1')"
65
+ expect(post.poster_comments.to_s).to eq soql
66
+ end
67
+
68
+ it 'should allow to add a where condition' do
69
+ soql = "SELECT Id, PostId, PosterId__c, FancyPostId, Body__c FROM Comment__c WHERE (1 = 0) AND (PostId = '1')"
70
+ expect(post.impossible_comments.to_s).to eq soql
71
+ end
72
+
73
+ it 'accepts custom scoping' do
74
+ soql = "SELECT Id, PostId, PosterId__c, FancyPostId, Body__c FROM Comment__c WHERE (Body__c = 'RE: Ham') AND (PostId = '1') ORDER BY CreationDate DESC"
75
+ expect(post.reply_comments.to_s).to eq soql
76
+ end
77
+
78
+ it 'accepts custom scoping that preloads associations of the association' do
79
+ account = Salesforce::Account.new id: '1', business_partner: 'qwerty'
80
+ soql = "SELECT Id, OwnerId, AccountId, Business_Partner__c, Owner.Id FROM Opportunity WHERE (Business_Partner__c = 'qwerty') AND (AccountId = '1')"
81
+ expect(account.partner_opportunities.to_s).to eq soql
82
+ end
83
+
84
+ it 'should use a convention name for the foreign key' do
85
+ soql = "SELECT Id, PostId, PosterId__c, FancyPostId, Body__c FROM Comment__c WHERE (PostId = '1')"
86
+ expect(post.comments.to_s).to eq soql
87
+ end
88
+ end
89
+
90
+ describe "belongs_to" do
91
+ it "should get the resource it belongs to" do
92
+ expect(comment.post).to be_instance_of(Post)
93
+ end
94
+
95
+ it "should allow to pass a foreign key as options" do
96
+ Comment.belongs_to :post, foreign_key: :fancy_post_id
97
+ allow(comment).to receive(:fancy_post_id).and_return "2"
98
+ expect(client).to receive(:query).with("SELECT Id, Title__c FROM Post__c WHERE (Id = '2') LIMIT 1")
99
+ comment.post
100
+ Comment.belongs_to :post # reset association to original value
101
+ end
102
+
103
+ it 'makes only one API call to fetch the associated object' do
104
+ expect(client).to receive(:query).once
105
+ comment.post
106
+ comment.post
107
+ end
108
+
109
+ describe "assignments" do
110
+ let(:comment) do
111
+ comment = Comment.new(id: '1')
112
+ comment.post = Post.new(id: '1')
113
+ comment
114
+ end
115
+
116
+ before do
117
+ expect(client).to_not receive(:query)
118
+ end
119
+
120
+ it 'accepts assignment of an existing object as an association' do
121
+ expect(client).to_not receive(:query)
122
+ other_post = Post.new(id: "2")
123
+ comment.post = other_post
124
+ expect(comment.post_id).to eq other_post.id
125
+ expect(comment.post).to eq other_post
126
+ end
127
+
128
+ it 'can desassociate an object by setting it as nil' do
129
+ comment.post = nil
130
+ expect(comment.post_id).to eq nil
131
+ expect(comment.post).to eq nil
132
+ end
133
+ end
134
+
135
+ context 'when the SObject is namespaced' do
136
+ let(:attachment){ Foo::Attachment.new(id: '1', lead_id: '2') }
137
+
138
+ it 'generates the correct query' do
139
+ expect(client).to receive(:query).with("SELECT Id FROM Lead WHERE (Id = '2') LIMIT 1")
140
+ attachment.lead
141
+ end
142
+
143
+ it 'instantiates the correct object' do
144
+ expect(attachment.lead).to be_instance_of(Foo::Lead)
145
+ end
146
+
147
+ context 'when given a foreign key' do
148
+ let(:attachment){ Foo::Attachment.new(id: '1', fancy_lead_id: '2') }
149
+
150
+ it 'generates the correct query' do
151
+ expect(client).to receive(:query).with("SELECT Id FROM Lead WHERE (Id = '2') LIMIT 1")
152
+ attachment.fancy_lead
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveForce::Attribute do
4
+ let(:attribute) { ActiveForce::Attribute }
5
+
6
+ describe 'initialize' do
7
+ let(:some_field) { attribute.new(:some_field) }
8
+
9
+ it 'should set "from" and "as" as default' do
10
+ expect(some_field.sfdc_name).to eq 'Some_Field__c'
11
+ expect(some_field.as).to eq :string
12
+ end
13
+
14
+ it 'should take values from the option parameter' do
15
+ other_field = attribute.new(:other_field, sfdc_name: 'OT__c', as: :integer)
16
+ expect(other_field.sfdc_name).to eq 'OT__c'
17
+ expect(other_field.as).to eq :integer
18
+ end
19
+ end
20
+
21
+ describe 'when the attribute is' do
22
+ it 'a multipick should return all values as 1 string separated with ";"' do
23
+ names = attribute.new(:names, as: :multi_picklist)
24
+ expect(names.value_for_hash ['olvap', 'eloy']).to eq 'olvap;eloy'
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveForce::SObject do
4
+ let(:client) { double 'Client', create!: 'id' }
5
+
6
+ before do
7
+ ActiveForce.sfdc_client = client
8
+ end
9
+
10
+ describe "save" do
11
+ it 'call action callback when save a record' do
12
+ whizbanged = Whizbang.new
13
+ whizbanged.save
14
+ expect(whizbanged.updated_from).to eq 'Rails'
15
+ expect(whizbanged.dirty_attribute).to eq true
16
+ expect(whizbanged.changed.include? 'dirty_attribute').to eq true
17
+ expect(whizbanged.changed.include? 'updated_from').to eq false
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveForce::Mapping do
4
+ let(:mapping){ ActiveForce::Mapping.new 'some_table' }
5
+
6
+ describe 'field' do
7
+ it 'should add a new attribute to the instance' do
8
+ mapping.field :id, from: 'Id'
9
+ expect(mapping.mappings).to eq({ id: 'Id' })
10
+ end
11
+
12
+ it 'sf_names should return all attributes names from salesforce' do
13
+ mapping.field :id, from: 'Id'
14
+ mapping.field :name, from: 'Name'
15
+ expect(mapping.sfdc_names).to eq ['Id', 'Name']
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,126 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveForce::Query do
4
+ let(:query) do
5
+ query = ActiveForce::Query.new 'table_name'
6
+ query.fields ['name', 'etc']
7
+ query
8
+ end
9
+
10
+ describe '.select' do
11
+ it 'use column sent on the select method' do
12
+ expect(query.select('name').all.to_s).to eq "SELECT name FROM table_name"
13
+ end
14
+
15
+ it 'use columns sent on the select method' do
16
+ expect(query.select(['id','name']).all.to_s).to eq "SELECT id, name FROM table_name"
17
+ end
18
+ end
19
+
20
+ describe ".all" do
21
+ it "table should return table name" do
22
+ expect(query.all.table).to eq(query.table)
23
+ end
24
+
25
+ it "fields should return fields" do
26
+ expect(query.all.fields).to eq query.fields
27
+ end
28
+ end
29
+
30
+ describe ".all.to_s" do
31
+ it "should return a query for all records" do
32
+ expect(query.all.to_s).to eq "SELECT Id, name, etc FROM table_name"
33
+ end
34
+
35
+ it "should ignore dupicated attributes in select statment" do
36
+ query.fields ['Id', 'name', 'etc']
37
+ expect(query.all.to_s).to eq "SELECT Id, name, etc FROM table_name"
38
+ end
39
+ end
40
+
41
+ describe ".where" do
42
+ it "should add a where condition to a query" do
43
+ expect(query.where("name like '%a%'").to_s).to eq "SELECT Id, name, etc FROM table_name WHERE (name like '%a%')"
44
+ end
45
+
46
+ it "should add multiples conditions to a query with parentheses" do
47
+ expect(query.where("condition1 = 1").where("condition2 = 2 OR condition3 = 3").to_s).to eq "SELECT Id, name, etc FROM table_name WHERE (condition1 = 1) AND (condition2 = 2 OR condition3 = 3)"
48
+ end
49
+ end
50
+
51
+ describe ".limit" do
52
+ it "should add a limit to a query" do
53
+ expect(query.limit("25").to_s).to eq "SELECT Id, name, etc FROM table_name LIMIT 25"
54
+ end
55
+ end
56
+
57
+ describe ".limit_value" do
58
+ it "should return the limit value" do
59
+ query.limit(4)
60
+ expect(query.limit_value).to eq 4
61
+ end
62
+ end
63
+
64
+ describe ".offset" do
65
+ it "should add an offset to a query" do
66
+ expect(query.offset(4).to_s).to eq "SELECT Id, name, etc FROM table_name OFFSET 4"
67
+ end
68
+ end
69
+
70
+ describe ".offset_value" do
71
+ it "should return the offset value" do
72
+ query.offset(4)
73
+ expect(query.offset_value).to eq 4
74
+ end
75
+ end
76
+
77
+ describe ".find.to_s" do
78
+ it "should return a query for 1 record" do
79
+ expect(query.find(2).to_s).to eq "SELECT Id, name, etc FROM table_name WHERE (Id = '2') LIMIT 1"
80
+ end
81
+ end
82
+
83
+ describe ".order" do
84
+ it "should add a order condition in the statment" do
85
+ expect(query.order("name desc").to_s).to eq "SELECT Id, name, etc FROM table_name ORDER BY name desc"
86
+ end
87
+
88
+ it "should add a order condition in the statment with WHERE and LIMIT" do
89
+ expect(query.where("condition1 = 1").order("name desc").limit(1).to_s).to eq "SELECT Id, name, etc FROM table_name WHERE (condition1 = 1) ORDER BY name desc LIMIT 1"
90
+ end
91
+ end
92
+
93
+ describe '.join' do
94
+ let(:join_query) do
95
+ join = ActiveForce::Query.new 'join_table_name'
96
+ join.fields ['name', 'etc']
97
+ join
98
+ end
99
+
100
+ it 'should add another select statment on the current select' do
101
+ expect(query.join(join_query).to_s).to eq 'SELECT Id, name, etc, (SELECT Id, name, etc FROM join_table_name) FROM table_name'
102
+ end
103
+ end
104
+
105
+ describe '.first' do
106
+ it 'should return the query for the first record' do
107
+ expect(query.first.to_s).to eq 'SELECT Id, name, etc FROM table_name LIMIT 1'
108
+ end
109
+ end
110
+
111
+ describe '.last' do
112
+ it 'should return the query for the last record' do
113
+ expect(query.last.to_s).to eq 'SELECT Id, name, etc FROM table_name ORDER BY Id DESC LIMIT 1'
114
+ end
115
+ end
116
+
117
+ describe ".count" do
118
+ it "should return the query for getting the row count" do
119
+ expect(query.count.to_s).to eq 'SELECT count(Id) FROM table_name'
120
+ end
121
+
122
+ it "should work with a condition" do
123
+ expect(query.where("name = 'cool'").count.to_s).to eq "SELECT count(Id) FROM table_name WHERE (name = 'cool')"
124
+ end
125
+ end
126
+ end