active_force 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/lib/active_force/active_query.rb +16 -24
- data/lib/active_force/association/association.rb +8 -0
- data/lib/active_force/association/eager_load_projection_builder.rb +12 -4
- data/lib/active_force/query.rb +32 -26
- data/lib/active_force/sobject.rb +9 -1
- data/lib/active_force/version.rb +1 -1
- data/spec/active_force/active_query_spec.rb +167 -60
- data/spec/active_force/association_spec.rb +10 -0
- data/spec/active_force/query_spec.rb +78 -7
- data/spec/active_force/sobject/includes_spec.rb +26 -2
- data/spec/active_force/sobject_spec.rb +73 -6
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6de1df55a3215360cd78f76fa3f55d05ca9e8f9f9603d5ab4257667a5fd961a5
|
4
|
+
data.tar.gz: e85f2ae5bd075070adc261ec3a6d566eea2f9cf19c4d4423fa1b859cafdabcc4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5268395d3fcc92a705b909026b6de6deb36b4c6a9b622d0ee63307ed08d16142e96abca2bafb902c55fca02955d75c34aa3348eb84fc14c47784d3548b492f89
|
7
|
+
data.tar.gz: 3ea676afd55bb62601e211250c487a86e7902f1dee1f8b6fdc41410b903ce2052e5a4f893cc869798ba3bf5c1270aad2c84ea21c24dd137909e494e7c0564ff9
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,17 @@
|
|
2
2
|
|
3
3
|
## Not released
|
4
4
|
|
5
|
+
## 0.18.0
|
6
|
+
|
7
|
+
- Fix eager loading of scoped associations. (https://github.com/Beyond-Finance/active_force/pull/67)
|
8
|
+
- Adding `.blank?`, `.present?`, and `.any?` delegators to `ActiveQuery`. (https://github.com/Beyond-Finance/active_force/pull/68)
|
9
|
+
- Adding `update` and `update!` class methods on `SObject`. (https://github.com/Beyond-Finance/active_force/pull/66)
|
10
|
+
- Allow an argument to `last` allowing the query to select the `last(n)` records. Default is 1. (https://github.com/Beyond-Finance/active_force/pull/66)
|
11
|
+
|
12
|
+
## 0.17.0
|
13
|
+
|
14
|
+
- Fix bug with has_many queries due to query method chaining mutating in-place (https://github.com/Beyond-Finance/active_force/pull/10)
|
15
|
+
|
5
16
|
## 0.16.0
|
6
17
|
|
7
18
|
- Fix `default` in models when default value is overridden by the same value, it is still sent to salesforce (https://github.com/Beyond-Finance/active_force/pull/61)
|
@@ -21,9 +21,9 @@ module ActiveForce
|
|
21
21
|
attr_reader :sobject, :association_mapping, :belongs_to_association_mapping
|
22
22
|
|
23
23
|
def_delegators :sobject, :sfdc_client, :build, :table_name, :mappings
|
24
|
-
def_delegators :to_a, :each, :map, :inspect, :pluck, :each_with_object
|
24
|
+
def_delegators :to_a, :blank?, :present?, :any?, :each, :map, :inspect, :pluck, :each_with_object
|
25
25
|
|
26
|
-
def initialize
|
26
|
+
def initialize(sobject, custom_table_name = nil)
|
27
27
|
@sobject = sobject
|
28
28
|
@association_mapping = {}
|
29
29
|
@belongs_to_association_mapping = {}
|
@@ -42,36 +42,34 @@ module ActiveForce
|
|
42
42
|
alias_method :all, :to_a
|
43
43
|
|
44
44
|
def count
|
45
|
-
super
|
46
|
-
sfdc_client.query(to_s).first.expr0
|
45
|
+
sfdc_client.query(super.to_s).first.expr0
|
47
46
|
end
|
48
47
|
|
49
48
|
def sum field
|
50
|
-
|
51
|
-
|
49
|
+
raise ArgumentError, 'field is required' if field.blank?
|
50
|
+
raise ArgumentError, "field '#{field}' does not exist on #{sobject}" unless mappings.key?(field.to_sym)
|
51
|
+
|
52
|
+
sfdc_client.query(super(mappings.fetch(field.to_sym)).to_s).first.expr0
|
52
53
|
end
|
53
54
|
|
54
55
|
def limit limit
|
55
|
-
super
|
56
|
-
limit == 1 ? to_a.first : self
|
56
|
+
limit == 1 ? super.to_a.first : super
|
57
57
|
end
|
58
58
|
|
59
59
|
def not args=nil, *rest
|
60
60
|
return self if args.nil?
|
61
|
+
|
61
62
|
super build_condition args, rest
|
62
|
-
self
|
63
63
|
end
|
64
64
|
|
65
65
|
def where args=nil, *rest
|
66
66
|
return self if args.nil?
|
67
|
-
return clone_self_and_clear_cache.where(args, *rest) if @decorated_records.present?
|
68
67
|
super build_condition args, rest
|
69
|
-
self
|
70
68
|
end
|
71
69
|
|
72
|
-
def select *
|
73
|
-
|
74
|
-
super *
|
70
|
+
def select *selected_fields
|
71
|
+
selected_fields.map! { |field| mappings[field] }
|
72
|
+
super *selected_fields
|
75
73
|
end
|
76
74
|
|
77
75
|
def find!(id)
|
@@ -100,8 +98,10 @@ module ActiveForce
|
|
100
98
|
end
|
101
99
|
|
102
100
|
def none
|
103
|
-
|
104
|
-
|
101
|
+
clone_and_set_instance_variables(
|
102
|
+
records: [],
|
103
|
+
conditions: [build_condition(id: '1' * 18), build_condition(id: '0' * 18)]
|
104
|
+
)
|
105
105
|
end
|
106
106
|
|
107
107
|
def loaded?
|
@@ -205,13 +205,6 @@ module ActiveForce
|
|
205
205
|
sfdc_client.query(self.to_s)
|
206
206
|
end
|
207
207
|
|
208
|
-
def clone_self_and_clear_cache
|
209
|
-
new_query = self.clone
|
210
|
-
new_query.instance_variable_set(:@decorated_records, nil)
|
211
|
-
new_query.instance_variable_set(:@records, nil)
|
212
|
-
new_query
|
213
|
-
end
|
214
|
-
|
215
208
|
def build_order_by(args)
|
216
209
|
args.map do |arg|
|
217
210
|
case arg
|
@@ -228,6 +221,5 @@ module ActiveForce
|
|
228
221
|
def order_type(type)
|
229
222
|
type == :desc ? 'DESC' : 'ASC'
|
230
223
|
end
|
231
|
-
|
232
224
|
end
|
233
225
|
end
|
@@ -26,6 +26,14 @@ module ActiveForce
|
|
26
26
|
options[:relationship_name] || relation_model.to_s.constantize.table_name
|
27
27
|
end
|
28
28
|
|
29
|
+
def scoped_as
|
30
|
+
options[:scoped_as] || nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def scoped?
|
34
|
+
options[:scoped_as].present?
|
35
|
+
end
|
36
|
+
|
29
37
|
###
|
30
38
|
# Does this association's relation_model represent
|
31
39
|
# +sfdc_table_name+? Examples of +sfdc_table_name+
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module ActiveForce
|
2
2
|
module Association
|
3
|
+
class InvalidEagerLoadAssociation < StandardError; end
|
3
4
|
class EagerLoadProjectionBuilder
|
4
5
|
class << self
|
5
6
|
def build(association, parent_association_field = nil)
|
@@ -34,6 +35,13 @@ module ActiveForce
|
|
34
35
|
def projections
|
35
36
|
raise "Must define #{self.class.name}#projections"
|
36
37
|
end
|
38
|
+
|
39
|
+
def apply_association_scope(query)
|
40
|
+
return query unless association.scoped?
|
41
|
+
raise InvalidEagerLoadAssociation, "Cannot use scopes that expect arguments: #{association.relation_name}" if association.scoped_as.arity.positive?
|
42
|
+
|
43
|
+
query.instance_exec(&association.scoped_as)
|
44
|
+
end
|
37
45
|
end
|
38
46
|
|
39
47
|
class HasManyAssociationProjectionBuilder < AbstractProjectionBuilder
|
@@ -43,17 +51,17 @@ module ActiveForce
|
|
43
51
|
# to be pluralized
|
44
52
|
def projections
|
45
53
|
relationship_name = association.sfdc_association_field
|
46
|
-
query =
|
54
|
+
query = ActiveQuery.new(association.relation_model, relationship_name)
|
47
55
|
query.fields association.relation_model.fields
|
48
|
-
["(#{query.to_s})"]
|
56
|
+
["(#{apply_association_scope(query).to_s})"]
|
49
57
|
end
|
50
58
|
end
|
51
59
|
|
52
60
|
class HasOneAssociationProjectionBuilder < AbstractProjectionBuilder
|
53
61
|
def projections
|
54
|
-
query =
|
62
|
+
query = ActiveQuery.new(association.relation_model, association.sfdc_association_field)
|
55
63
|
query.fields association.relation_model.fields
|
56
|
-
["(#{query.to_s})"]
|
64
|
+
["(#{apply_association_scope(query).to_s})"]
|
57
65
|
end
|
58
66
|
end
|
59
67
|
|
data/lib/active_force/query.rb
CHANGED
@@ -31,33 +31,34 @@ module ActiveForce
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def select *columns
|
34
|
-
|
35
|
-
|
34
|
+
clone_and_set_instance_variables(query_fields: columns)
|
35
|
+
end
|
36
|
+
|
37
|
+
def where condition = nil
|
38
|
+
new_conditions = @conditions | [condition]
|
39
|
+
if new_conditions != @conditions
|
40
|
+
clone_and_set_instance_variables({conditions: new_conditions})
|
41
|
+
else
|
42
|
+
self
|
43
|
+
end
|
36
44
|
end
|
37
45
|
|
38
46
|
def not condition
|
39
|
-
|
40
|
-
self
|
47
|
+
condition ? where("NOT ((#{condition.join(') AND (')}))") : self
|
41
48
|
end
|
42
49
|
|
43
50
|
def or query
|
44
|
-
|
45
|
-
self
|
46
|
-
end
|
51
|
+
return self unless query
|
47
52
|
|
48
|
-
|
49
|
-
@conditions << condition if condition
|
50
|
-
self
|
53
|
+
clone_and_set_instance_variables(conditions: ["(#{and_conditions}) OR (#{query.and_conditions})"])
|
51
54
|
end
|
52
55
|
|
53
56
|
def order order
|
54
|
-
|
55
|
-
self
|
57
|
+
order ? clone_and_set_instance_variables(order: order) : self
|
56
58
|
end
|
57
59
|
|
58
60
|
def limit size
|
59
|
-
|
60
|
-
self
|
61
|
+
size ? clone_and_set_instance_variables(size: size) : self
|
61
62
|
end
|
62
63
|
|
63
64
|
def limit_value
|
@@ -65,8 +66,7 @@ module ActiveForce
|
|
65
66
|
end
|
66
67
|
|
67
68
|
def offset offset
|
68
|
-
|
69
|
-
self
|
69
|
+
clone_and_set_instance_variables(offset: offset)
|
70
70
|
end
|
71
71
|
|
72
72
|
def offset_value
|
@@ -74,31 +74,29 @@ module ActiveForce
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def find id
|
77
|
-
where
|
78
|
-
limit 1
|
77
|
+
where("#{ @table_id } = '#{ id }'").limit 1
|
79
78
|
end
|
80
79
|
|
81
80
|
def first
|
82
81
|
limit 1
|
83
82
|
end
|
84
83
|
|
85
|
-
def last
|
86
|
-
order("Id DESC").limit(
|
84
|
+
def last(limit = 1)
|
85
|
+
order("Id DESC").limit(limit)
|
87
86
|
end
|
88
87
|
|
89
88
|
def join object_query
|
90
|
-
|
91
|
-
|
89
|
+
chained_query = self.clone
|
90
|
+
chained_query.fields ["(#{ object_query.to_s })"]
|
91
|
+
chained_query
|
92
92
|
end
|
93
93
|
|
94
94
|
def count
|
95
|
-
|
96
|
-
self
|
95
|
+
clone_and_set_instance_variables(query_fields: ["count(Id)"])
|
97
96
|
end
|
98
97
|
|
99
98
|
def sum field
|
100
|
-
|
101
|
-
self
|
99
|
+
clone_and_set_instance_variables(query_fields: ["sum(#{field})"])
|
102
100
|
end
|
103
101
|
|
104
102
|
protected
|
@@ -125,5 +123,13 @@ module ActiveForce
|
|
125
123
|
def build_offset
|
126
124
|
"OFFSET #{ @offset }" if @offset
|
127
125
|
end
|
126
|
+
|
127
|
+
def clone_and_set_instance_variables instance_variable_hash={}
|
128
|
+
clone = self.clone
|
129
|
+
clone.instance_variable_set(:@decorated_records, nil)
|
130
|
+
clone.instance_variable_set(:@records, nil)
|
131
|
+
instance_variable_hash.each { |k,v| clone.instance_variable_set("@#{k.to_s}", v) }
|
132
|
+
clone
|
133
|
+
end
|
128
134
|
end
|
129
135
|
end
|
data/lib/active_force/sobject.rb
CHANGED
@@ -129,6 +129,14 @@ module ActiveForce
|
|
129
129
|
new(args).create!
|
130
130
|
end
|
131
131
|
|
132
|
+
def self.update(id, attributes)
|
133
|
+
new(attributes.merge(id: id)).update
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.update!(id, attributes)
|
137
|
+
new(attributes.merge(id: id)).update!
|
138
|
+
end
|
139
|
+
|
132
140
|
def save!
|
133
141
|
run_callbacks :save do
|
134
142
|
if persisted?
|
@@ -231,7 +239,7 @@ module ActiveForce
|
|
231
239
|
end
|
232
240
|
|
233
241
|
def default_attributes
|
234
|
-
@attributes.each_value.select do |value|
|
242
|
+
@attributes.each_value.select do |value|
|
235
243
|
value.is_a?(ActiveModel::Attribute::UserProvidedDefault) || value.instance_values["original_attribute"].is_a?(ActiveModel::Attribute::UserProvidedDefault)
|
236
244
|
end.map(&:name)
|
237
245
|
end
|
data/lib/active_force/version.rb
CHANGED
@@ -9,7 +9,7 @@ describe ActiveForce::ActiveQuery do
|
|
9
9
|
})
|
10
10
|
end
|
11
11
|
let(:mappings){ { id: "Id", field: "Field__c", other_field: "Other_Field" } }
|
12
|
-
let(:client){ double(
|
12
|
+
let(:client) { double('client', query: nil) }
|
13
13
|
let(:active_query){ described_class.new(sobject) }
|
14
14
|
let(:api_result) do
|
15
15
|
[
|
@@ -18,7 +18,6 @@ describe ActiveForce::ActiveQuery do
|
|
18
18
|
]
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
21
|
before do
|
23
22
|
allow(active_query).to receive(:sfdc_client).and_return client
|
24
23
|
allow(active_query).to receive(:build).and_return Object.new
|
@@ -40,50 +39,113 @@ describe ActiveForce::ActiveQuery do
|
|
40
39
|
end
|
41
40
|
end
|
42
41
|
|
42
|
+
describe '#blank? delegation' do
|
43
|
+
before do
|
44
|
+
allow(client).to receive(:query).and_return(api_result)
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when there are no records' do
|
48
|
+
let(:api_result) { [] }
|
49
|
+
|
50
|
+
it 'returns true' do
|
51
|
+
result = active_query.where("Text_Label = 'foo'").blank?
|
52
|
+
expect(result).to be true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when records are returned' do
|
57
|
+
it 'returns false' do
|
58
|
+
result = active_query.where("Text_Label = 'foo'").blank?
|
59
|
+
expect(result).to be false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#present? delegation' do
|
65
|
+
before do
|
66
|
+
allow(client).to receive(:query).and_return(api_result)
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when there are no records' do
|
70
|
+
let(:api_result) { [] }
|
71
|
+
|
72
|
+
it 'returns false' do
|
73
|
+
result = active_query.where("Text_Label = 'foo'").present?
|
74
|
+
expect(result).to be false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'when there are records' do
|
79
|
+
it 'returns true' do
|
80
|
+
result = active_query.where("Text_Label = 'foo'").present?
|
81
|
+
expect(result).to be true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#any? delegation' do
|
87
|
+
before do
|
88
|
+
allow(client).to receive(:query).and_return(api_result)
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'when there are no records' do
|
92
|
+
let(:api_result) { [] }
|
93
|
+
|
94
|
+
it 'returns true' do
|
95
|
+
result = active_query.where("Text_Label = 'foo'").any?
|
96
|
+
expect(result).to be false
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when records are returned' do
|
101
|
+
it 'returns false' do
|
102
|
+
result = active_query.where("Text_Label = 'foo'").any?
|
103
|
+
expect(result).to be true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
43
108
|
describe "select only some field using mappings" do
|
44
109
|
it "should return a query only with selected field" do
|
45
|
-
active_query.select(:field)
|
46
|
-
expect(
|
110
|
+
new_query = active_query.select(:field)
|
111
|
+
expect(new_query.to_s).to eq("SELECT Field__c FROM table_name")
|
47
112
|
end
|
48
113
|
end
|
49
114
|
|
50
115
|
describe "condition mapping" do
|
51
116
|
it "maps conditions for a .where" do
|
52
|
-
active_query.where(field: 123)
|
53
|
-
expect(
|
117
|
+
new_query = active_query.where(field: 123)
|
118
|
+
expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123)")
|
54
119
|
end
|
55
120
|
|
56
121
|
it 'transforms an array to a WHERE/IN clause' do
|
57
|
-
active_query.where(field: ['foo', 'bar'])
|
58
|
-
expect(
|
122
|
+
new_query = active_query.where(field: ['foo', 'bar'])
|
123
|
+
expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c IN ('foo','bar'))")
|
59
124
|
end
|
60
125
|
|
61
126
|
it "encloses the value in quotes if it's a string" do
|
62
|
-
active_query.where field: "hello"
|
63
|
-
expect(
|
127
|
+
new_query = active_query.where field: "hello"
|
128
|
+
expect(new_query.to_s).to end_with("(Field__c = 'hello')")
|
64
129
|
end
|
65
130
|
|
66
131
|
it "formats as YYYY-MM-DDThh:mm:ss-hh:mm and does not enclose in quotes if it's a DateTime" do
|
67
132
|
value = DateTime.now
|
68
|
-
active_query.where(field: value)
|
69
|
-
expect(active_query.to_s).to end_with("(Field__c = #{value.iso8601})")
|
133
|
+
expect(active_query.where(field: value).to_s).to end_with("(Field__c = #{value.iso8601})")
|
70
134
|
end
|
71
135
|
|
72
136
|
it "formats as YYYY-MM-DDThh:mm:ss-hh:mm and does not enclose in quotes if it's a Time" do
|
73
137
|
value = Time.now
|
74
|
-
active_query.where(field: value)
|
75
|
-
expect(active_query.to_s).to end_with("(Field__c = #{value.iso8601})")
|
138
|
+
expect(active_query.where(field: value).to_s).to end_with("(Field__c = #{value.iso8601})")
|
76
139
|
end
|
77
140
|
|
78
141
|
it "formats as YYYY-MM-DD and does not enclose in quotes if it's a Date" do
|
79
142
|
value = Date.today
|
80
|
-
active_query.where(field: value)
|
81
|
-
expect(active_query.to_s).to end_with("(Field__c = #{value.iso8601})")
|
143
|
+
expect(active_query.where(field: value).to_s).to end_with("(Field__c = #{value.iso8601})")
|
82
144
|
end
|
83
145
|
|
84
146
|
it "puts NULL when a field is set as nil" do
|
85
|
-
active_query.where field: nil
|
86
|
-
expect(
|
147
|
+
new_query = active_query.where field: nil
|
148
|
+
expect(new_query.to_s).to end_with("(Field__c = NULL)")
|
87
149
|
end
|
88
150
|
|
89
151
|
describe 'bind parameters' do
|
@@ -95,36 +157,33 @@ describe ActiveForce::ActiveQuery do
|
|
95
157
|
end
|
96
158
|
|
97
159
|
it 'accepts bind parameters' do
|
98
|
-
active_query.where('Field__c = ?', 123)
|
99
|
-
expect(
|
160
|
+
new_query = active_query.where('Field__c = ?', 123)
|
161
|
+
expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123)")
|
100
162
|
end
|
101
163
|
|
102
164
|
it 'accepts nil bind parameters' do
|
103
|
-
active_query.where('Field__c = ?', nil)
|
104
|
-
expect(
|
165
|
+
new_query = active_query.where('Field__c = ?', nil)
|
166
|
+
expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = NULL)")
|
105
167
|
end
|
106
168
|
|
107
169
|
it 'accepts multiple bind parameters' do
|
108
|
-
active_query.where('Field__c = ? AND Other_Field__c = ? AND Name = ?', 123, 321, 'Bob')
|
109
|
-
expect(
|
170
|
+
new_query = active_query.where('Field__c = ? AND Other_Field__c = ? AND Name = ?', 123, 321, 'Bob')
|
171
|
+
expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123 AND Other_Field__c = 321 AND Name = 'Bob')")
|
110
172
|
end
|
111
173
|
|
112
174
|
it 'formats as YYYY-MM-DDThh:mm:ss-hh:mm and does not enclose in quotes if value is a DateTime' do
|
113
175
|
value = DateTime.now
|
114
|
-
active_query.where('Field__c > ?', value)
|
115
|
-
expect(active_query.to_s).to end_with("(Field__c > #{value.iso8601})")
|
176
|
+
expect(active_query.where('Field__c > ?', value).to_s).to end_with("(Field__c > #{value.iso8601})")
|
116
177
|
end
|
117
178
|
|
118
179
|
it 'formats as YYYY-MM-DDThh:mm:ss-hh:mm and does not enclose in quotes if value is a Time' do
|
119
180
|
value = Time.now
|
120
|
-
active_query.where('Field__c > ?', value)
|
121
|
-
expect(active_query.to_s).to end_with("(Field__c > #{value.iso8601})")
|
181
|
+
expect(active_query.where('Field__c > ?', value).to_s).to end_with("(Field__c > #{value.iso8601})")
|
122
182
|
end
|
123
183
|
|
124
184
|
it 'formats as YYYY-MM-DD and does not enclose in quotes if value is a Date' do
|
125
185
|
value = Date.today
|
126
|
-
active_query.where('Field__c > ?', value)
|
127
|
-
expect(active_query.to_s).to end_with("(Field__c > #{value.iso8601})")
|
186
|
+
expect(active_query.where('Field__c > ?', value).to_s).to end_with("(Field__c > #{value.iso8601})")
|
128
187
|
end
|
129
188
|
|
130
189
|
it 'complains when there given an incorrect number of bind parameters' do
|
@@ -135,41 +194,41 @@ describe ActiveForce::ActiveQuery do
|
|
135
194
|
|
136
195
|
context 'named bind parameters' do
|
137
196
|
it 'accepts bind parameters' do
|
138
|
-
active_query.where('Field__c = :field', field: 123)
|
139
|
-
expect(
|
197
|
+
new_query = active_query.where('Field__c = :field', field: 123)
|
198
|
+
expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123)")
|
140
199
|
end
|
141
200
|
|
142
201
|
it 'accepts nil bind parameters' do
|
143
|
-
active_query.where('Field__c = :field', field: nil)
|
144
|
-
expect(
|
202
|
+
new_query = active_query.where('Field__c = :field', field: nil)
|
203
|
+
expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = NULL)")
|
145
204
|
end
|
146
205
|
|
147
206
|
it 'formats as YYYY-MM-DDThh:mm:ss-hh:mm and does not enclose in quotes if value is a DateTime' do
|
148
207
|
value = DateTime.now
|
149
|
-
active_query.where('Field__c < :field', field: value)
|
150
|
-
expect(
|
208
|
+
new_query = active_query.where('Field__c < :field', field: value)
|
209
|
+
expect(new_query.to_s).to end_with("(Field__c < #{value.iso8601})")
|
151
210
|
end
|
152
211
|
|
153
212
|
it 'formats as YYYY-MM-DDThh:mm:ss-hh:mm and does not enclose in quotes if value is a Time' do
|
154
213
|
value = Time.now
|
155
|
-
active_query.where('Field__c < :field', field: value)
|
156
|
-
expect(
|
214
|
+
new_query = active_query.where('Field__c < :field', field: value)
|
215
|
+
expect(new_query.to_s).to end_with("(Field__c < #{value.iso8601})")
|
157
216
|
end
|
158
217
|
|
159
218
|
it 'formats as YYYY-MM-DD and does not enclose in quotes if value is a Date' do
|
160
219
|
value = Date.today
|
161
|
-
active_query.where('Field__c < :field', field: value)
|
162
|
-
expect(
|
220
|
+
new_query = active_query.where('Field__c < :field', field: value)
|
221
|
+
expect(new_query.to_s).to end_with("(Field__c < #{value.iso8601})")
|
163
222
|
end
|
164
223
|
|
165
224
|
it 'accepts multiple bind parameters' do
|
166
|
-
active_query.where('Field__c = :field AND Other_Field__c = :other_field AND Name = :name', field: 123, other_field: 321, name: 'Bob')
|
167
|
-
expect(
|
225
|
+
new_query = active_query.where('Field__c = :field AND Other_Field__c = :other_field AND Name = :name', field: 123, other_field: 321, name: 'Bob')
|
226
|
+
expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123 AND Other_Field__c = 321 AND Name = 'Bob')")
|
168
227
|
end
|
169
228
|
|
170
229
|
it 'accepts multiple bind parameters orderless' do
|
171
|
-
active_query.where('Field__c = :field AND Other_Field__c = :other_field AND Name = :name', name: 'Bob', other_field: 321, field: 123)
|
172
|
-
expect(
|
230
|
+
new_query = active_query.where('Field__c = :field AND Other_Field__c = :other_field AND Name = :name', name: 'Bob', other_field: 321, field: 123)
|
231
|
+
expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123 AND Other_Field__c = 321 AND Name = 'Bob')")
|
173
232
|
end
|
174
233
|
|
175
234
|
it 'complains when there given an incorrect number of bind parameters' do
|
@@ -198,29 +257,77 @@ describe ActiveForce::ActiveQuery do
|
|
198
257
|
{"Id" => "0000000000EEEEEFFF"}
|
199
258
|
]
|
200
259
|
end
|
260
|
+
|
201
261
|
it 'allows method chaining' do
|
202
262
|
result = active_query.where("Text_Label = 'foo'").where("Checkbox_Label = true")
|
203
263
|
expect(result).to be_a described_class
|
204
264
|
end
|
205
265
|
|
266
|
+
it 'does not execute a query' do
|
267
|
+
active_query.where('x')
|
268
|
+
expect(client).not_to have_received(:query)
|
269
|
+
end
|
270
|
+
|
271
|
+
context 'when calling `where` on an ActiveQuery object that already has records' do
|
272
|
+
context 'after the query result has been decorated' do
|
273
|
+
it 'returns a new ActiveQuery object' do
|
274
|
+
first_active_query = active_query.where("Text_Label = 'foo'")
|
275
|
+
first_active_query.to_a # decorates the results
|
276
|
+
second_active_query = first_active_query.where("Checkbox_Label = true")
|
277
|
+
second_active_query.to_a
|
278
|
+
expect(second_active_query).to be_a described_class
|
279
|
+
expect(second_active_query).not_to eq first_active_query
|
280
|
+
expect(second_active_query.to_s).not_to eq first_active_query.to_s
|
281
|
+
expect(second_active_query.to_a.size).to eq(1)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
206
286
|
context 'when calling `where` on an ActiveQuery object that already has records' do
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
287
|
+
context 'without the query result being decorated' do
|
288
|
+
|
289
|
+
it 'returns a new ActiveQuery object' do
|
290
|
+
first_active_query = active_query.where("Text_Label = 'foo'")
|
291
|
+
second_active_query = first_active_query.where("Checkbox_Label = true")
|
292
|
+
expect(second_active_query).to be_a described_class
|
293
|
+
expect(second_active_query).not_to eq first_active_query
|
294
|
+
expect(second_active_query.to_s).not_to eq first_active_query.to_s
|
295
|
+
expect(second_active_query.to_a.size).to eq(1)
|
296
|
+
end
|
214
297
|
end
|
215
298
|
end
|
299
|
+
end
|
216
300
|
|
301
|
+
describe '#not' do
|
302
|
+
it 'adds a not condition' do
|
303
|
+
expect(active_query.not(field: 'x').to_s).to end_with("WHERE (NOT ((Field__c = 'x')))")
|
304
|
+
end
|
305
|
+
|
306
|
+
it 'allows chaining' do
|
307
|
+
expect(active_query.where(field: 'x').not(field: 'y').where(field: 'z')).to be_a(described_class)
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'does not mutate the original query' do
|
311
|
+
original = active_query.to_s
|
312
|
+
active_query.not(field: 'x')
|
313
|
+
expect(active_query.to_s).to eq(original)
|
314
|
+
end
|
315
|
+
|
316
|
+
it 'returns the original query if not given a condition' do
|
317
|
+
expect(active_query.not).to be(active_query)
|
318
|
+
end
|
319
|
+
|
320
|
+
it 'does not execute a query' do
|
321
|
+
active_query.not(field: 'x')
|
322
|
+
expect(client).not_to have_received(:query)
|
323
|
+
end
|
217
324
|
end
|
218
325
|
|
219
326
|
describe "#find_by" do
|
220
327
|
it "should query the client, with the SFDC field names and correctly enclosed values" do
|
221
|
-
expect(client).to receive
|
222
|
-
active_query.find_by field: 123
|
223
|
-
expect(
|
328
|
+
expect(client).to receive(:query).with("SELECT Id FROM table_name WHERE (Field__c = 123) LIMIT 1")
|
329
|
+
new_query = active_query.find_by field: 123
|
330
|
+
expect(new_query).to be_nil
|
224
331
|
end
|
225
332
|
end
|
226
333
|
|
@@ -290,18 +397,18 @@ describe ActiveForce::ActiveQuery do
|
|
290
397
|
let(:expected_query){ "SELECT Id FROM table_name WHERE (Backslash_Field__c = '\\\\' AND NumberField = 123 AND QuoteField = '\\' OR Id!=NULL OR Id=\\'')" }
|
291
398
|
|
292
399
|
it 'escapes quotes and backslashes in bind parameters' do
|
293
|
-
active_query.where('Backslash_Field__c = :backslash_field AND NumberField = :number_field AND QuoteField = :quote_field', number_field: number_input, backslash_field: backslash_input, quote_field: quote_input)
|
294
|
-
expect(
|
400
|
+
new_query = active_query.where('Backslash_Field__c = :backslash_field AND NumberField = :number_field AND QuoteField = :quote_field', number_field: number_input, backslash_field: backslash_input, quote_field: quote_input)
|
401
|
+
expect(new_query.to_s).to eq(expected_query)
|
295
402
|
end
|
296
403
|
|
297
404
|
it 'escapes quotes and backslashes in named bind parameters' do
|
298
|
-
active_query.where('Backslash_Field__c = ? AND NumberField = ? AND QuoteField = ?', backslash_input, number_input, quote_input)
|
299
|
-
expect(
|
405
|
+
new_query = active_query.where('Backslash_Field__c = ? AND NumberField = ? AND QuoteField = ?', backslash_input, number_input, quote_input)
|
406
|
+
expect(new_query.to_s).to eq(expected_query)
|
300
407
|
end
|
301
408
|
|
302
409
|
it 'escapes quotes and backslashes in hash conditions' do
|
303
|
-
active_query.where(backslash_field: backslash_input, number_field: number_input, quote_field: quote_input)
|
304
|
-
expect(
|
410
|
+
new_query = active_query.where(backslash_field: backslash_input, number_field: number_input, quote_field: quote_input)
|
411
|
+
expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Backslash_Field__c = '\\\\') AND (NumberField = 123) AND (QuoteField = '\\' OR Id!=NULL OR Id=\\'')")
|
305
412
|
end
|
306
413
|
end
|
307
414
|
|
@@ -40,6 +40,16 @@ describe ActiveForce::SObject do
|
|
40
40
|
post.comments.to_a
|
41
41
|
end
|
42
42
|
|
43
|
+
it 'is not mutated by #where' do
|
44
|
+
post.comments.where(body: 'test').to_a
|
45
|
+
expect(post.comments.to_s).to end_with("FROM Comment__c WHERE (PostId = '1')")
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'is not mutated by #none' do
|
49
|
+
post.comments.none.to_a
|
50
|
+
expect(post.comments.to_s).to end_with("FROM Comment__c WHERE (PostId = '1')")
|
51
|
+
end
|
52
|
+
|
43
53
|
describe 'to_s' do
|
44
54
|
it "should return a SOQL statment" do
|
45
55
|
soql = "SELECT Id, PostId, PosterId__c, FancyPostId, Body__c FROM Comment__c WHERE (PostId = '1')"
|
@@ -32,7 +32,7 @@ describe ActiveForce::Query do
|
|
32
32
|
expect(query.all.to_s).to eq "SELECT Id, name, etc FROM table_name"
|
33
33
|
end
|
34
34
|
|
35
|
-
it "should ignore
|
35
|
+
it "should ignore duplicated attributes in select statment" do
|
36
36
|
query.fields ['Id', 'name', 'etc']
|
37
37
|
expect(query.all.to_s).to eq "SELECT Id, name, etc FROM table_name"
|
38
38
|
end
|
@@ -46,6 +46,19 @@ describe ActiveForce::Query do
|
|
46
46
|
it "should add multiples conditions to a query with parentheses" do
|
47
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
48
|
end
|
49
|
+
|
50
|
+
it "should not duplicate conditions" do
|
51
|
+
first_query = query.where("name = 'cool'").where("foo = 'baz'")
|
52
|
+
second_query = first_query.where("name = 'cool'")
|
53
|
+
expect(first_query.to_s).to eq(second_query.to_s)
|
54
|
+
expect(first_query.object_id).to eq(second_query.object_id)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should not update the original query" do
|
58
|
+
new_query = query.where("name = 'cool'")
|
59
|
+
expect(query.to_s).to eq "SELECT Id, name, etc FROM table_name"
|
60
|
+
expect(new_query.to_s).to eq "SELECT Id, name, etc FROM table_name WHERE (name = 'cool')"
|
61
|
+
end
|
49
62
|
end
|
50
63
|
|
51
64
|
describe ".not" do
|
@@ -68,12 +81,18 @@ describe ActiveForce::Query do
|
|
68
81
|
it "should add a limit to a query" do
|
69
82
|
expect(query.limit("25").to_s).to eq "SELECT Id, name, etc FROM table_name LIMIT 25"
|
70
83
|
end
|
84
|
+
|
85
|
+
it "should not update the original query" do
|
86
|
+
new_query = query.limit("25")
|
87
|
+
expect(query.to_s).to eq "SELECT Id, name, etc FROM table_name"
|
88
|
+
expect(new_query.to_s).to eq "SELECT Id, name, etc FROM table_name LIMIT 25"
|
89
|
+
end
|
71
90
|
end
|
72
91
|
|
73
92
|
describe ".limit_value" do
|
74
93
|
it "should return the limit value" do
|
75
|
-
query.limit(4)
|
76
|
-
expect(
|
94
|
+
new_query = query.limit(4)
|
95
|
+
expect(new_query.limit_value).to eq 4
|
77
96
|
end
|
78
97
|
end
|
79
98
|
|
@@ -81,12 +100,18 @@ describe ActiveForce::Query do
|
|
81
100
|
it "should add an offset to a query" do
|
82
101
|
expect(query.offset(4).to_s).to eq "SELECT Id, name, etc FROM table_name OFFSET 4"
|
83
102
|
end
|
103
|
+
|
104
|
+
it "should not update the original query" do
|
105
|
+
new_query = query.offset(4)
|
106
|
+
expect(query.to_s).to eq "SELECT Id, name, etc FROM table_name"
|
107
|
+
expect(new_query.to_s).to eq "SELECT Id, name, etc FROM table_name OFFSET 4"
|
108
|
+
end
|
84
109
|
end
|
85
110
|
|
86
111
|
describe ".offset_value" do
|
87
112
|
it "should return the offset value" do
|
88
|
-
query.offset(4)
|
89
|
-
expect(
|
113
|
+
new_query = query.offset(4)
|
114
|
+
expect(new_query.offset_value).to eq 4
|
90
115
|
end
|
91
116
|
end
|
92
117
|
|
@@ -104,6 +129,12 @@ describe ActiveForce::Query do
|
|
104
129
|
it "should add a order condition in the statment with WHERE and LIMIT" do
|
105
130
|
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"
|
106
131
|
end
|
132
|
+
|
133
|
+
it "should not update the original query" do
|
134
|
+
ordered_query = query.order("name desc")
|
135
|
+
expect(query.to_s).to eq "SELECT Id, name, etc FROM table_name"
|
136
|
+
expect(ordered_query.to_s).to eq "SELECT Id, name, etc FROM table_name ORDER BY name desc"
|
137
|
+
end
|
107
138
|
end
|
108
139
|
|
109
140
|
describe '.join' do
|
@@ -116,17 +147,51 @@ describe ActiveForce::Query do
|
|
116
147
|
it 'should add another select statment on the current select' do
|
117
148
|
expect(query.join(join_query).to_s).to eq 'SELECT Id, name, etc, (SELECT Id, name, etc FROM join_table_name) FROM table_name'
|
118
149
|
end
|
150
|
+
|
151
|
+
it "should not update the original query" do
|
152
|
+
new_query = query.join(join_query)
|
153
|
+
expect(query.to_s).to eq "SELECT Id, name, etc FROM table_name"
|
154
|
+
expect(new_query.to_s).to eq 'SELECT Id, name, etc, (SELECT Id, name, etc FROM join_table_name) FROM table_name'
|
155
|
+
end
|
119
156
|
end
|
120
157
|
|
121
158
|
describe '.first' do
|
122
159
|
it 'should return the query for the first record' do
|
123
160
|
expect(query.first.to_s).to eq 'SELECT Id, name, etc FROM table_name LIMIT 1'
|
124
161
|
end
|
162
|
+
|
163
|
+
it "should not update the original query" do
|
164
|
+
new_query = query.first
|
165
|
+
expect(query.to_s).to eq "SELECT Id, name, etc FROM table_name"
|
166
|
+
expect(new_query.to_s).to eq 'SELECT Id, name, etc FROM table_name LIMIT 1'
|
167
|
+
end
|
125
168
|
end
|
126
169
|
|
127
170
|
describe '.last' do
|
128
|
-
|
129
|
-
|
171
|
+
context 'without any argument' do
|
172
|
+
it 'should return the query for the last record' do
|
173
|
+
expect(query.last.to_s).to eq 'SELECT Id, name, etc FROM table_name ORDER BY Id DESC LIMIT 1'
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should not update the original query" do
|
177
|
+
new_query = query.last
|
178
|
+
expect(query.to_s).to eq "SELECT Id, name, etc FROM table_name"
|
179
|
+
expect(new_query.to_s).to eq 'SELECT Id, name, etc FROM table_name ORDER BY Id DESC LIMIT 1'
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context 'with an argument' do
|
184
|
+
let(:last_argument) { 3 }
|
185
|
+
|
186
|
+
it 'should return the query for the last n records' do
|
187
|
+
expect(query.last(last_argument).to_s).to eq "SELECT Id, name, etc FROM table_name ORDER BY Id DESC LIMIT #{last_argument}"
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should not update the original query" do
|
191
|
+
new_query = query.last last_argument
|
192
|
+
expect(query.to_s).to eq "SELECT Id, name, etc FROM table_name"
|
193
|
+
expect(new_query.to_s).to eq "SELECT Id, name, etc FROM table_name ORDER BY Id DESC LIMIT #{last_argument}"
|
194
|
+
end
|
130
195
|
end
|
131
196
|
end
|
132
197
|
|
@@ -138,6 +203,12 @@ describe ActiveForce::Query do
|
|
138
203
|
it "should work with a condition" do
|
139
204
|
expect(query.where("name = 'cool'").count.to_s).to eq "SELECT count(Id) FROM table_name WHERE (name = 'cool')"
|
140
205
|
end
|
206
|
+
|
207
|
+
it "should not update the original query" do
|
208
|
+
query_with_count = query.where("name = 'cool'").count
|
209
|
+
expect(query.to_s).to eq "SELECT Id, name, etc FROM table_name"
|
210
|
+
expect(query_with_count.to_s).to eq "SELECT count(Id) FROM table_name WHERE (name = 'cool')"
|
211
|
+
end
|
141
212
|
end
|
142
213
|
|
143
214
|
describe ".sum" do
|
@@ -225,6 +225,13 @@ module ActiveForce
|
|
225
225
|
end
|
226
226
|
end
|
227
227
|
|
228
|
+
context 'when assocation has a scope' do
|
229
|
+
it 'formulates the correct SOQL query with the scope applied' do
|
230
|
+
soql = Post.includes(:impossible_comments).where(id: '1234').to_s
|
231
|
+
expect(soql).to eq "SELECT Id, Title__c, BlogId, (SELECT Id, PostId, PosterId__c, FancyPostId, Body__c FROM Comments__r WHERE (1 = 0)) FROM Post__c WHERE (Id = '1234')"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
228
235
|
context 'with namespaced SObjects' do
|
229
236
|
it 'formulates the correct SOQL query' do
|
230
237
|
soql = Salesforce::Quota.includes(:prez_clubs).where(id: '123').to_s
|
@@ -286,9 +293,26 @@ module ActiveForce
|
|
286
293
|
end
|
287
294
|
end
|
288
295
|
|
296
|
+
context 'has_one' do
|
297
|
+
context 'when assocation has a scope' do
|
298
|
+
it 'formulates the correct SOQL query with the scope applied' do
|
299
|
+
soql = Post.includes(:last_comment).where(id: '1234').to_s
|
300
|
+
expect(soql).to eq "SELECT Id, Title__c, BlogId, (SELECT Id, PostId, PosterId__c, FancyPostId, Body__c FROM Comment__r WHERE (NOT ((Body__c = NULL))) ORDER BY CreatedDate DESC) FROM Post__c WHERE (Id = '1234')"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
end
|
305
|
+
|
289
306
|
context 'when invalid associations are passed' do
|
290
|
-
|
291
|
-
|
307
|
+
context 'when the association is not defined' do
|
308
|
+
it 'raises an error' do
|
309
|
+
expect { Quota.includes(:invalid).find('123') }.to raise_error(ActiveForce::Association::InvalidAssociationError, 'Association named invalid was not found on Quota')
|
310
|
+
end
|
311
|
+
end
|
312
|
+
context 'when the association is scoped and accepts an argument' do
|
313
|
+
it 'raises and error' do
|
314
|
+
expect { Post.includes(:reply_comments).find('1234')}.to raise_error(ActiveForce::Association::InvalidEagerLoadAssociation)
|
315
|
+
end
|
292
316
|
end
|
293
317
|
end
|
294
318
|
end
|
@@ -313,20 +313,87 @@ describe ActiveForce::SObject do
|
|
313
313
|
expect(Whizbang.create(text: 'some text')).to be_instance_of(Whizbang)
|
314
314
|
end
|
315
315
|
end
|
316
|
+
|
317
|
+
describe 'self.update' do
|
318
|
+
it 'uses the client to update the correct record' do
|
319
|
+
expect(client).to receive(:update!)
|
320
|
+
.with(Whizbang.table_name, { 'Id' => '12345678', 'Text_Label' => 'my text', 'Updated_From__c' => 'Rails' })
|
321
|
+
.and_return(true)
|
322
|
+
Whizbang.update('12345678', text: 'my text')
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
describe 'self.update!' do
|
327
|
+
it 'uses the client to update the correct record' do
|
328
|
+
expect(client).to receive(:update!)
|
329
|
+
.with(Whizbang.table_name, { 'Id' => '123456789', 'Text_Label' => 'some other text', 'Updated_From__c' => 'Rails' })
|
330
|
+
.and_return(true)
|
331
|
+
Whizbang.update('123456789', text: 'some other text')
|
332
|
+
end
|
333
|
+
end
|
316
334
|
end
|
317
335
|
|
318
|
-
describe
|
319
|
-
let(:
|
336
|
+
describe '.count' do
|
337
|
+
let(:response) { [Restforce::Mash.new(expr0: 1)] }
|
338
|
+
|
339
|
+
before do
|
340
|
+
allow(client).to receive(:query).and_return(response)
|
341
|
+
end
|
320
342
|
|
321
|
-
it
|
322
|
-
|
343
|
+
it 'sends the correct query to the client' do
|
344
|
+
expected = 'SELECT count(Id) FROM Whizbang__c'
|
345
|
+
Whizbang.count
|
346
|
+
expect(client).to have_received(:query).with(expected)
|
323
347
|
end
|
324
348
|
|
325
|
-
it
|
326
|
-
expect(client).to receive(:query).and_return(count_response)
|
349
|
+
it 'returns the result from the response' do
|
327
350
|
expect(Whizbang.count).to eq(1)
|
328
351
|
end
|
329
352
|
|
353
|
+
it 'works with .where' do
|
354
|
+
expected = 'SELECT count(Id) FROM Whizbang__c WHERE (Boolean_Label = true)'
|
355
|
+
Whizbang.where(boolean: true).count
|
356
|
+
expect(client).to have_received(:query).with(expected)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
describe '.sum' do
|
361
|
+
let(:response) { [Restforce::Mash.new(expr0: 22)] }
|
362
|
+
|
363
|
+
before do
|
364
|
+
allow(client).to receive(:query).and_return(response)
|
365
|
+
end
|
366
|
+
|
367
|
+
it 'raises ArgumentError if given blank' do
|
368
|
+
expect { Whizbang.sum(nil) }.to raise_error(ArgumentError, 'field is required')
|
369
|
+
end
|
370
|
+
|
371
|
+
it 'raises ArgumentError if given invalid field' do
|
372
|
+
expect { Whizbang.sum(:invalid) }
|
373
|
+
.to raise_error(ArgumentError, /field 'invalid' does not exist on Whizbang/i)
|
374
|
+
end
|
375
|
+
|
376
|
+
it 'sends the correct query to the client' do
|
377
|
+
expected = 'SELECT sum(Percent_Label) FROM Whizbang__c'
|
378
|
+
Whizbang.sum(:percent)
|
379
|
+
expect(client).to have_received(:query).with(expected)
|
380
|
+
end
|
381
|
+
|
382
|
+
it 'works when given a string field' do
|
383
|
+
expected = 'SELECT sum(Percent_Label) FROM Whizbang__c'
|
384
|
+
Whizbang.sum('percent')
|
385
|
+
expect(client).to have_received(:query).with(expected)
|
386
|
+
end
|
387
|
+
|
388
|
+
it 'returns the result from the response' do
|
389
|
+
expect(Whizbang.sum(:percent)).to eq(22)
|
390
|
+
end
|
391
|
+
|
392
|
+
it 'works with .where' do
|
393
|
+
expected = 'SELECT sum(Percent_Label) FROM Whizbang__c WHERE (Boolean_Label = true)'
|
394
|
+
Whizbang.where(boolean: true).sum(:percent)
|
395
|
+
expect(client).to have_received(:query).with(expected)
|
396
|
+
end
|
330
397
|
end
|
331
398
|
|
332
399
|
describe "#find_by" do
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_force
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.18.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eloy Espinaco
|
8
8
|
- Pablo Oldani
|
9
9
|
- Armando Andini
|
10
10
|
- José Piccioni
|
11
|
-
autorequire:
|
11
|
+
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2023-
|
14
|
+
date: 2023-10-02 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: activemodel
|
@@ -193,7 +193,7 @@ metadata:
|
|
193
193
|
bug_tracker_uri: https://github.com/Beyond-Finance/active_force/issues
|
194
194
|
changelog_uri: https://github.com/Beyond-Finance/active_force/blob/main/CHANGELOG.md
|
195
195
|
source_code_uri: https://github.com/Beyond-Finance/active_force
|
196
|
-
post_install_message:
|
196
|
+
post_install_message:
|
197
197
|
rdoc_options: []
|
198
198
|
require_paths:
|
199
199
|
- lib
|
@@ -208,8 +208,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
208
208
|
- !ruby/object:Gem::Version
|
209
209
|
version: '0'
|
210
210
|
requirements: []
|
211
|
-
rubygems_version: 3.
|
212
|
-
signing_key:
|
211
|
+
rubygems_version: 3.3.26
|
212
|
+
signing_key:
|
213
213
|
specification_version: 4
|
214
214
|
summary: Help you implement models persisting on Sales Force within Rails using RESTForce
|
215
215
|
test_files:
|