active_force 0.16.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7691f9f6f82d893a6aafdf29cfc6228ab2fe31988fafcf5be95070347a0286de
4
- data.tar.gz: 4d0da25e5e12f9014407dba1871953a0b05f58227188d53130eba27dd537aa4d
3
+ metadata.gz: 741f33a6c27d6bc11eaaa7655c2a7fb2ecc772f93d298e608866840b82e94321
4
+ data.tar.gz: 465abe2c572e35dc61817ab1bf8ac1d6d0e35e6f26eb2e933af3ed1781c2c68a
5
5
  SHA512:
6
- metadata.gz: 2e8cf96c34eb81e3e4236455538bc462de07d02f7149ab064125d4c86f52a96c7e61e98ff91b9fe48e3b5b6d79d88ded4bb47966800f021e153a970adac802b4
7
- data.tar.gz: 6b7edaa7cf4161921b1d42c3a26fe896781bd3198ce981b2693852f3fe3ff6f1690e27e61ec781761fbe06d10634fc720013f1b2f3a266d3de6a189dd37af2a5
6
+ metadata.gz: 376ab891dc3a0bf92f030dd3b756aa900c8091bfd42b3424ef1c832ecc2ac14384785f96eeadc20764f22ee02315753cba10c4b0aec067294e2175a09754dc60
7
+ data.tar.gz: f60cf65275aaee5e96ebb173cc0718cbc663b3cced951bccf8b417df1029055606be56bdf82617e689130d68687b8ce8f8227acab83314c54715e95e6ca28629
data/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## Not released
4
4
 
5
+ ## 0.17.0
6
+
7
+ - Fix bug with has_many queries due to query method chaining mutating in-place (https://github.com/Beyond-Finance/active_force/pull/10)
8
+
5
9
  ## 0.16.0
6
10
 
7
11
  - 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)
@@ -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
- super(mappings[field])
51
- sfdc_client.query(to_s).first.expr0
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 *fields
73
- fields.map! { |field| mappings[field] }
74
- super *fields
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
- @records = []
104
- where(id: '1'*18).where(id: '0'*18)
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
@@ -31,33 +31,34 @@ module ActiveForce
31
31
  end
32
32
 
33
33
  def select *columns
34
- @query_fields = columns
35
- self
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
- @conditions << "NOT ((#{ condition.join(') AND (') }))"
40
- self
47
+ condition ? where("NOT ((#{condition.join(') AND (')}))") : self
41
48
  end
42
49
 
43
50
  def or query
44
- @conditions = ["(#{ and_conditions }) OR (#{ query.and_conditions })"]
45
- self
46
- end
51
+ return self unless query
47
52
 
48
- def where condition = nil
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
- @order = order if order
55
- self
57
+ order ? clone_and_set_instance_variables(order: order) : self
56
58
  end
57
59
 
58
60
  def limit size
59
- @size = size if size
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
- @offset = offset
69
- self
69
+ clone_and_set_instance_variables(offset: offset)
70
70
  end
71
71
 
72
72
  def offset_value
@@ -74,8 +74,7 @@ module ActiveForce
74
74
  end
75
75
 
76
76
  def find id
77
- where "#{ @table_id } = '#{ id }'"
78
- limit 1
77
+ where("#{ @table_id } = '#{ id }'").limit 1
79
78
  end
80
79
 
81
80
  def first
@@ -87,18 +86,17 @@ module ActiveForce
87
86
  end
88
87
 
89
88
  def join object_query
90
- fields ["(#{ object_query.to_s })"]
91
- self
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
- @query_fields = ["count(Id)"]
96
- self
95
+ clone_and_set_instance_variables(query_fields: ["count(Id)"])
97
96
  end
98
97
 
99
98
  def sum field
100
- @query_fields = ["sum(#{field})"]
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveForce
4
- VERSION = '0.16.0'
4
+ VERSION = '0.17.0'
5
5
  end
@@ -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("client") }
12
+ let(:client) { double('client', query: nil) }
13
13
  let(:active_query){ described_class.new(sobject) }
14
14
  let(:api_result) do
15
15
  [
@@ -42,48 +42,45 @@ describe ActiveForce::ActiveQuery do
42
42
 
43
43
  describe "select only some field using mappings" do
44
44
  it "should return a query only with selected field" do
45
- active_query.select(:field)
46
- expect(active_query.to_s).to eq("SELECT Field__c FROM table_name")
45
+ new_query = active_query.select(:field)
46
+ expect(new_query.to_s).to eq("SELECT Field__c FROM table_name")
47
47
  end
48
48
  end
49
49
 
50
50
  describe "condition mapping" do
51
51
  it "maps conditions for a .where" do
52
- active_query.where(field: 123)
53
- expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123)")
52
+ new_query = active_query.where(field: 123)
53
+ expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123)")
54
54
  end
55
55
 
56
56
  it 'transforms an array to a WHERE/IN clause' do
57
- active_query.where(field: ['foo', 'bar'])
58
- expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c IN ('foo','bar'))")
57
+ new_query = active_query.where(field: ['foo', 'bar'])
58
+ expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c IN ('foo','bar'))")
59
59
  end
60
60
 
61
61
  it "encloses the value in quotes if it's a string" do
62
- active_query.where field: "hello"
63
- expect(active_query.to_s).to end_with("(Field__c = 'hello')")
62
+ new_query = active_query.where field: "hello"
63
+ expect(new_query.to_s).to end_with("(Field__c = 'hello')")
64
64
  end
65
65
 
66
66
  it "formats as YYYY-MM-DDThh:mm:ss-hh:mm and does not enclose in quotes if it's a DateTime" do
67
67
  value = DateTime.now
68
- active_query.where(field: value)
69
- expect(active_query.to_s).to end_with("(Field__c = #{value.iso8601})")
68
+ expect(active_query.where(field: value).to_s).to end_with("(Field__c = #{value.iso8601})")
70
69
  end
71
70
 
72
71
  it "formats as YYYY-MM-DDThh:mm:ss-hh:mm and does not enclose in quotes if it's a Time" do
73
72
  value = Time.now
74
- active_query.where(field: value)
75
- expect(active_query.to_s).to end_with("(Field__c = #{value.iso8601})")
73
+ expect(active_query.where(field: value).to_s).to end_with("(Field__c = #{value.iso8601})")
76
74
  end
77
75
 
78
76
  it "formats as YYYY-MM-DD and does not enclose in quotes if it's a Date" do
79
77
  value = Date.today
80
- active_query.where(field: value)
81
- expect(active_query.to_s).to end_with("(Field__c = #{value.iso8601})")
78
+ expect(active_query.where(field: value).to_s).to end_with("(Field__c = #{value.iso8601})")
82
79
  end
83
80
 
84
81
  it "puts NULL when a field is set as nil" do
85
- active_query.where field: nil
86
- expect(active_query.to_s).to end_with("(Field__c = NULL)")
82
+ new_query = active_query.where field: nil
83
+ expect(new_query.to_s).to end_with("(Field__c = NULL)")
87
84
  end
88
85
 
89
86
  describe 'bind parameters' do
@@ -95,36 +92,33 @@ describe ActiveForce::ActiveQuery do
95
92
  end
96
93
 
97
94
  it 'accepts bind parameters' do
98
- active_query.where('Field__c = ?', 123)
99
- expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123)")
95
+ new_query = active_query.where('Field__c = ?', 123)
96
+ expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123)")
100
97
  end
101
98
 
102
99
  it 'accepts nil bind parameters' do
103
- active_query.where('Field__c = ?', nil)
104
- expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = NULL)")
100
+ new_query = active_query.where('Field__c = ?', nil)
101
+ expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = NULL)")
105
102
  end
106
103
 
107
104
  it 'accepts multiple bind parameters' do
108
- active_query.where('Field__c = ? AND Other_Field__c = ? AND Name = ?', 123, 321, 'Bob')
109
- expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123 AND Other_Field__c = 321 AND Name = 'Bob')")
105
+ new_query = active_query.where('Field__c = ? AND Other_Field__c = ? AND Name = ?', 123, 321, 'Bob')
106
+ 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
107
  end
111
108
 
112
109
  it 'formats as YYYY-MM-DDThh:mm:ss-hh:mm and does not enclose in quotes if value is a DateTime' do
113
110
  value = DateTime.now
114
- active_query.where('Field__c > ?', value)
115
- expect(active_query.to_s).to end_with("(Field__c > #{value.iso8601})")
111
+ expect(active_query.where('Field__c > ?', value).to_s).to end_with("(Field__c > #{value.iso8601})")
116
112
  end
117
113
 
118
114
  it 'formats as YYYY-MM-DDThh:mm:ss-hh:mm and does not enclose in quotes if value is a Time' do
119
115
  value = Time.now
120
- active_query.where('Field__c > ?', value)
121
- expect(active_query.to_s).to end_with("(Field__c > #{value.iso8601})")
116
+ expect(active_query.where('Field__c > ?', value).to_s).to end_with("(Field__c > #{value.iso8601})")
122
117
  end
123
118
 
124
119
  it 'formats as YYYY-MM-DD and does not enclose in quotes if value is a Date' do
125
120
  value = Date.today
126
- active_query.where('Field__c > ?', value)
127
- expect(active_query.to_s).to end_with("(Field__c > #{value.iso8601})")
121
+ expect(active_query.where('Field__c > ?', value).to_s).to end_with("(Field__c > #{value.iso8601})")
128
122
  end
129
123
 
130
124
  it 'complains when there given an incorrect number of bind parameters' do
@@ -135,41 +129,41 @@ describe ActiveForce::ActiveQuery do
135
129
 
136
130
  context 'named bind parameters' do
137
131
  it 'accepts bind parameters' do
138
- active_query.where('Field__c = :field', field: 123)
139
- expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123)")
132
+ new_query = active_query.where('Field__c = :field', field: 123)
133
+ expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123)")
140
134
  end
141
135
 
142
136
  it 'accepts nil bind parameters' do
143
- active_query.where('Field__c = :field', field: nil)
144
- expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = NULL)")
137
+ new_query = active_query.where('Field__c = :field', field: nil)
138
+ expect(new_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = NULL)")
145
139
  end
146
140
 
147
141
  it 'formats as YYYY-MM-DDThh:mm:ss-hh:mm and does not enclose in quotes if value is a DateTime' do
148
142
  value = DateTime.now
149
- active_query.where('Field__c < :field', field: value)
150
- expect(active_query.to_s).to end_with("(Field__c < #{value.iso8601})")
143
+ new_query = active_query.where('Field__c < :field', field: value)
144
+ expect(new_query.to_s).to end_with("(Field__c < #{value.iso8601})")
151
145
  end
152
146
 
153
147
  it 'formats as YYYY-MM-DDThh:mm:ss-hh:mm and does not enclose in quotes if value is a Time' do
154
148
  value = Time.now
155
- active_query.where('Field__c < :field', field: value)
156
- expect(active_query.to_s).to end_with("(Field__c < #{value.iso8601})")
149
+ new_query = active_query.where('Field__c < :field', field: value)
150
+ expect(new_query.to_s).to end_with("(Field__c < #{value.iso8601})")
157
151
  end
158
152
 
159
153
  it 'formats as YYYY-MM-DD and does not enclose in quotes if value is a Date' do
160
154
  value = Date.today
161
- active_query.where('Field__c < :field', field: value)
162
- expect(active_query.to_s).to end_with("(Field__c < #{value.iso8601})")
155
+ new_query = active_query.where('Field__c < :field', field: value)
156
+ expect(new_query.to_s).to end_with("(Field__c < #{value.iso8601})")
163
157
  end
164
158
 
165
159
  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(active_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123 AND Other_Field__c = 321 AND Name = 'Bob')")
160
+ new_query = active_query.where('Field__c = :field AND Other_Field__c = :other_field AND Name = :name', field: 123, other_field: 321, name: 'Bob')
161
+ 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
162
  end
169
163
 
170
164
  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(active_query.to_s).to eq("SELECT Id FROM table_name WHERE (Field__c = 123 AND Other_Field__c = 321 AND Name = 'Bob')")
165
+ new_query = active_query.where('Field__c = :field AND Other_Field__c = :other_field AND Name = :name', name: 'Bob', other_field: 321, field: 123)
166
+ 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
167
  end
174
168
 
175
169
  it 'complains when there given an incorrect number of bind parameters' do
@@ -198,29 +192,77 @@ describe ActiveForce::ActiveQuery do
198
192
  {"Id" => "0000000000EEEEEFFF"}
199
193
  ]
200
194
  end
195
+
201
196
  it 'allows method chaining' do
202
197
  result = active_query.where("Text_Label = 'foo'").where("Checkbox_Label = true")
203
198
  expect(result).to be_a described_class
204
199
  end
205
200
 
201
+ it 'does not execute a query' do
202
+ active_query.where('x')
203
+ expect(client).not_to have_received(:query)
204
+ end
205
+
206
+ context 'when calling `where` on an ActiveQuery object that already has records' do
207
+ context 'after the query result has been decorated' do
208
+ it 'returns a new ActiveQuery object' do
209
+ first_active_query = active_query.where("Text_Label = 'foo'")
210
+ first_active_query.to_a # decorates the results
211
+ second_active_query = first_active_query.where("Checkbox_Label = true")
212
+ second_active_query.to_a
213
+ expect(second_active_query).to be_a described_class
214
+ expect(second_active_query).not_to eq first_active_query
215
+ expect(second_active_query.to_s).not_to eq first_active_query.to_s
216
+ expect(second_active_query.to_a.size).to eq(1)
217
+ end
218
+ end
219
+ end
220
+
206
221
  context 'when calling `where` on an ActiveQuery object that already has records' do
207
- it 'returns a new ActiveQuery object' do
208
- first_active_query = active_query.where("Text_Label = 'foo'")
209
- first_active_query.inspect # so the query is executed
210
- second_active_query = first_active_query.where("Checkbox_Label = true")
211
- second_active_query.inspect
212
- expect(second_active_query).to be_a described_class
213
- expect(second_active_query).not_to eq first_active_query
222
+ context 'without the query result being decorated' do
223
+
224
+ it 'returns a new ActiveQuery object' do
225
+ first_active_query = active_query.where("Text_Label = 'foo'")
226
+ second_active_query = first_active_query.where("Checkbox_Label = true")
227
+ expect(second_active_query).to be_a described_class
228
+ expect(second_active_query).not_to eq first_active_query
229
+ expect(second_active_query.to_s).not_to eq first_active_query.to_s
230
+ expect(second_active_query.to_a.size).to eq(1)
231
+ end
214
232
  end
215
233
  end
234
+ end
216
235
 
236
+ describe '#not' do
237
+ it 'adds a not condition' do
238
+ expect(active_query.not(field: 'x').to_s).to end_with("WHERE (NOT ((Field__c = 'x')))")
239
+ end
240
+
241
+ it 'allows chaining' do
242
+ expect(active_query.where(field: 'x').not(field: 'y').where(field: 'z')).to be_a(described_class)
243
+ end
244
+
245
+ it 'does not mutate the original query' do
246
+ original = active_query.to_s
247
+ active_query.not(field: 'x')
248
+ expect(active_query.to_s).to eq(original)
249
+ end
250
+
251
+ it 'returns the original query if not given a condition' do
252
+ expect(active_query.not).to be(active_query)
253
+ end
254
+
255
+ it 'does not execute a query' do
256
+ active_query.not(field: 'x')
257
+ expect(client).not_to have_received(:query)
258
+ end
217
259
  end
218
260
 
219
261
  describe "#find_by" do
220
262
  it "should query the client, with the SFDC field names and correctly enclosed values" do
221
- expect(client).to receive :query
222
- active_query.find_by field: 123
223
- expect(active_query.to_s).to eq "SELECT Id FROM table_name WHERE (Field__c = 123) LIMIT 1"
263
+ expect(client).to receive(:query).with("SELECT Id FROM table_name WHERE (Field__c = 123) LIMIT 1")
264
+ new_query = active_query.find_by field: 123
265
+ expect(new_query).to be_nil
224
266
  end
225
267
  end
226
268
 
@@ -290,18 +332,18 @@ describe ActiveForce::ActiveQuery do
290
332
  let(:expected_query){ "SELECT Id FROM table_name WHERE (Backslash_Field__c = '\\\\' AND NumberField = 123 AND QuoteField = '\\' OR Id!=NULL OR Id=\\'')" }
291
333
 
292
334
  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(active_query.to_s).to eq(expected_query)
335
+ 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)
336
+ expect(new_query.to_s).to eq(expected_query)
295
337
  end
296
338
 
297
339
  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(active_query.to_s).to eq(expected_query)
340
+ new_query = active_query.where('Backslash_Field__c = ? AND NumberField = ? AND QuoteField = ?', backslash_input, number_input, quote_input)
341
+ expect(new_query.to_s).to eq(expected_query)
300
342
  end
301
343
 
302
344
  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(active_query.to_s).to eq("SELECT Id FROM table_name WHERE (Backslash_Field__c = '\\\\') AND (NumberField = 123) AND (QuoteField = '\\' OR Id!=NULL OR Id=\\'')")
345
+ new_query = active_query.where(backslash_field: backslash_input, number_field: number_input, quote_field: quote_input)
346
+ 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
347
  end
306
348
  end
307
349
 
@@ -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 dupicated attributes in select statment" do
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(query.limit_value).to eq 4
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(query.offset_value).to eq 4
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,18 +147,36 @@ 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
171
  it 'should return the query for the last record' do
129
172
  expect(query.last.to_s).to eq 'SELECT Id, name, etc FROM table_name ORDER BY Id DESC LIMIT 1'
130
173
  end
174
+
175
+ it "should not update the original query" do
176
+ new_query = query.last
177
+ expect(query.to_s).to eq "SELECT Id, name, etc FROM table_name"
178
+ expect(new_query.to_s).to eq 'SELECT Id, name, etc FROM table_name ORDER BY Id DESC LIMIT 1'
179
+ end
131
180
  end
132
181
 
133
182
  describe ".count" do
@@ -138,6 +187,12 @@ describe ActiveForce::Query do
138
187
  it "should work with a condition" do
139
188
  expect(query.where("name = 'cool'").count.to_s).to eq "SELECT count(Id) FROM table_name WHERE (name = 'cool')"
140
189
  end
190
+
191
+ it "should not update the original query" do
192
+ query_with_count = query.where("name = 'cool'").count
193
+ expect(query.to_s).to eq "SELECT Id, name, etc FROM table_name"
194
+ expect(query_with_count.to_s).to eq "SELECT count(Id) FROM table_name WHERE (name = 'cool')"
195
+ end
141
196
  end
142
197
 
143
198
  describe ".sum" do
@@ -315,18 +315,67 @@ describe ActiveForce::SObject do
315
315
  end
316
316
  end
317
317
 
318
- describe "#count" do
319
- let(:count_response){ [Restforce::Mash.new(expr0: 1)] }
318
+ describe '.count' do
319
+ let(:response) { [Restforce::Mash.new(expr0: 1)] }
320
320
 
321
- it "responds to count" do
322
- expect(Whizbang).to respond_to(:count)
321
+ before do
322
+ allow(client).to receive(:query).and_return(response)
323
+ end
324
+
325
+ it 'sends the correct query to the client' do
326
+ expected = 'SELECT count(Id) FROM Whizbang__c'
327
+ Whizbang.count
328
+ expect(client).to have_received(:query).with(expected)
323
329
  end
324
330
 
325
- it "sends the query to the client" do
326
- expect(client).to receive(:query).and_return(count_response)
331
+ it 'returns the result from the response' do
327
332
  expect(Whizbang.count).to eq(1)
328
333
  end
329
334
 
335
+ it 'works with .where' do
336
+ expected = 'SELECT count(Id) FROM Whizbang__c WHERE (Boolean_Label = true)'
337
+ Whizbang.where(boolean: true).count
338
+ expect(client).to have_received(:query).with(expected)
339
+ end
340
+ end
341
+
342
+ describe '.sum' do
343
+ let(:response) { [Restforce::Mash.new(expr0: 22)] }
344
+
345
+ before do
346
+ allow(client).to receive(:query).and_return(response)
347
+ end
348
+
349
+ it 'raises ArgumentError if given blank' do
350
+ expect { Whizbang.sum(nil) }.to raise_error(ArgumentError, 'field is required')
351
+ end
352
+
353
+ it 'raises ArgumentError if given invalid field' do
354
+ expect { Whizbang.sum(:invalid) }
355
+ .to raise_error(ArgumentError, /field 'invalid' does not exist on Whizbang/i)
356
+ end
357
+
358
+ it 'sends the correct query to the client' do
359
+ expected = 'SELECT sum(Percent_Label) FROM Whizbang__c'
360
+ Whizbang.sum(:percent)
361
+ expect(client).to have_received(:query).with(expected)
362
+ end
363
+
364
+ it 'works when given a string field' do
365
+ expected = 'SELECT sum(Percent_Label) FROM Whizbang__c'
366
+ Whizbang.sum('percent')
367
+ expect(client).to have_received(:query).with(expected)
368
+ end
369
+
370
+ it 'returns the result from the response' do
371
+ expect(Whizbang.sum(:percent)).to eq(22)
372
+ end
373
+
374
+ it 'works with .where' do
375
+ expected = 'SELECT sum(Percent_Label) FROM Whizbang__c WHERE (Boolean_Label = true)'
376
+ Whizbang.where(boolean: true).sum(:percent)
377
+ expect(client).to have_received(:query).with(expected)
378
+ end
330
379
  end
331
380
 
332
381
  describe "#find_by" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_force
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eloy Espinaco
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2023-07-31 00:00:00.000000000 Z
14
+ date: 2023-08-23 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activemodel