active_force 0.23.0 → 0.25.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/.circleci/config.yml +6 -39
- data/.travis.yml +0 -2
- data/CHANGELOG.md +6 -0
- data/LICENSE.txt +8 -0
- data/README.md +11 -0
- data/active_force.gemspec +4 -3
- data/lib/active_force/active_query.rb +9 -4
- data/lib/active_force/association/eager_load_builder_for_nested_includes.rb +16 -8
- data/lib/active_force/association/eager_load_projection_builder.rb +13 -11
- data/lib/active_force/query.rb +1 -1
- data/lib/active_force/select_builder.rb +41 -0
- data/lib/active_force/sobject.rb +11 -2
- data/lib/active_force/version.rb +1 -1
- data/spec/active_force/sobject/includes_spec.rb +40 -0
- data/spec/active_force/sobject_spec.rb +14 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/whizbang.rb +4 -0
- metadata +22 -8
- data/.github/workflows +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2717b024f19c2c0dbf7530d606797a5880dfe629a154e6eebd083da381b917b1
|
4
|
+
data.tar.gz: ab29915f960873acd523a12f73af63f8c13b200e8cddbe4465ef28038cdebf2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc4aa9e5110884da1008add3a996387d66af6c337328d56e773457fb24e61410a63d5bd3a734ab5bf79a44c4b5962a55aca1c00314af41d1275df663fa133f16
|
7
|
+
data.tar.gz: 6702930b7f9d47c2290c4e00300160f5e3261ed9c22834ab4bef55a8438f6ec778f97e51aab197b23d10b1d2b6c6d20dc3e2991b728a847529cf16e7121d6983
|
data/.circleci/config.yml
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
version: 2
|
1
|
+
version: 2.1
|
2
|
+
|
3
|
+
orbs:
|
4
|
+
codecov: codecov/codecov@4.0.1
|
2
5
|
|
3
6
|
references:
|
4
7
|
default_docker_ruby_executor: &default_docker_ruby_executor
|
@@ -51,49 +54,16 @@ jobs:
|
|
51
54
|
key: active_force-{{ checksum "active_force.gemspec" }}
|
52
55
|
paths:
|
53
56
|
- ~/active_force/active_force_index/vendor/bundle
|
54
|
-
- run:
|
55
|
-
name: Install Code Climate Test Reporter
|
56
|
-
command: |
|
57
|
-
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
58
|
-
chmod +x ./cc-test-reporter
|
59
57
|
- run:
|
60
58
|
name: Run RSpec
|
61
59
|
command: |
|
62
60
|
mkdir /tmp/test-results
|
63
|
-
./cc-test-reporter before-build
|
64
61
|
TESTFILES=$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)
|
65
62
|
bundle exec rspec $TESTFILES --profile 10 --format RspecJunitFormatter --out /tmp/test-results/rspec.xml --format progress
|
66
|
-
-
|
67
|
-
name: Code Climate Test Coverage
|
68
|
-
command: |
|
69
|
-
./cc-test-reporter format-coverage -t simplecov -o "coverage/codeclimate.$CIRCLE_NODE_INDEX.json"
|
70
|
-
- persist_to_workspace:
|
71
|
-
root: coverage
|
72
|
-
paths:
|
73
|
-
- codeclimate.*.json
|
74
|
-
- store_test_results:
|
75
|
-
path: /tmp/test-results
|
76
|
-
- store_artifacts:
|
77
|
-
path: /tmp/test-results
|
78
|
-
destination: test-results
|
63
|
+
- codecov/upload
|
79
64
|
- store_artifacts:
|
80
65
|
path: coverage
|
81
|
-
|
82
|
-
working_directory: ~/active_force/active_force_index
|
83
|
-
docker:
|
84
|
-
- *default_docker_ruby_executor
|
85
|
-
steps:
|
86
|
-
- attach_workspace:
|
87
|
-
at: ~/active_force/active_force_index
|
88
|
-
- run:
|
89
|
-
name: Install Code Climate Test Reporter
|
90
|
-
command: |
|
91
|
-
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
92
|
-
chmod +x ./cc-test-reporter
|
93
|
-
- run:
|
94
|
-
name: Combine and Upload Coverage
|
95
|
-
command: |
|
96
|
-
./cc-test-reporter sum-coverage --output - codeclimate.*.json | ./cc-test-reporter upload-coverage --debug --input -
|
66
|
+
|
97
67
|
workflows:
|
98
68
|
version: 2
|
99
69
|
build_and_test:
|
@@ -102,6 +72,3 @@ workflows:
|
|
102
72
|
- rspec-test:
|
103
73
|
requires:
|
104
74
|
- build
|
105
|
-
- upload-coverage:
|
106
|
-
requires:
|
107
|
-
- rspec-test
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
## Not released
|
4
4
|
|
5
|
+
## 0.25.0
|
6
|
+
- Add support for Rails 8.x (https://github.com/Beyond-Finance/active_force/pull/108)
|
7
|
+
|
8
|
+
## 0.24.0
|
9
|
+
- Add support for nested select statements that are used in conjuction with nested includes (https://github.com/Beyond-Finance/active_force/pull/102)
|
10
|
+
|
5
11
|
## 0.23.0
|
6
12
|
- Partially addresses #90. `#select` accepts a block and returns an array of filtered SObjects. (https://github.com/Beyond-Finance/active_force/pull/99)
|
7
13
|
|
data/LICENSE.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
[Copyright © 2024 Beyond Finance, LLC.]
|
2
|
+
|
3
|
+
This library is available as open source under the terms of the
|
4
|
+
MIT License (https://opensource.org/license/mit). This library is
|
5
|
+
based on the open source code library "https://github.com/heroku/active_force" which was in turn forked from
|
6
|
+
"https://github.com/ionia-corporation/active_force" and licensed
|
7
|
+
under the MIT License.
|
8
|
+
|
1
9
|
Copyright (c) 2013 Eloy Espinaco
|
2
10
|
|
3
11
|
MIT License
|
data/README.md
CHANGED
@@ -218,6 +218,17 @@ Comment.includes(post: :owner)
|
|
218
218
|
Comment.includes({post: {owner: :account}})
|
219
219
|
```
|
220
220
|
|
221
|
+
You can also use #select with a multi level #includes.
|
222
|
+
|
223
|
+
Examples:
|
224
|
+
|
225
|
+
```ruby
|
226
|
+
Comment.select(:body, post: [:title, :is_active]).includes(post: :owner)
|
227
|
+
Comment.select(:body, account: :owner_id).includes({post: {owner: :account}})
|
228
|
+
```
|
229
|
+
|
230
|
+
The Sobject name in the #select must match the Sobject in the #includes for the fields to be filtered.
|
231
|
+
|
221
232
|
### Aggregates
|
222
233
|
|
223
234
|
Summing the values of a column:
|
data/active_force.gemspec
CHANGED
@@ -25,12 +25,13 @@ Gem::Specification.new do |spec|
|
|
25
25
|
|
26
26
|
spec.required_ruby_version = '>= 1.9.3'
|
27
27
|
|
28
|
-
spec.add_dependency 'activemodel', '
|
29
|
-
spec.add_dependency 'activesupport', '
|
28
|
+
spec.add_dependency 'activemodel', '>= 7.0'
|
29
|
+
spec.add_dependency 'activesupport', '>= 7.0'
|
30
30
|
spec.add_dependency 'restforce', '>= 5'
|
31
31
|
spec.add_development_dependency 'rake', '>= 0'
|
32
32
|
spec.add_development_dependency 'rspec', '>= 0'
|
33
33
|
spec.add_development_dependency 'rspec_junit_formatter'
|
34
34
|
spec.add_development_dependency 'pry', '>= 0'
|
35
|
-
spec.add_development_dependency 'simplecov'
|
35
|
+
spec.add_development_dependency 'simplecov'
|
36
|
+
spec.add_development_dependency 'simplecov-cobertura'
|
36
37
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_support/all'
|
2
2
|
require 'active_force/query'
|
3
|
+
require 'active_force/select_builder'
|
3
4
|
require 'forwardable'
|
4
5
|
|
5
6
|
module ActiveForce
|
@@ -25,7 +26,7 @@ module ActiveForce
|
|
25
26
|
class ActiveQuery < Query
|
26
27
|
extend Forwardable
|
27
28
|
|
28
|
-
attr_reader :sobject, :association_mapping, :belongs_to_association_mapping
|
29
|
+
attr_reader :sobject, :association_mapping, :belongs_to_association_mapping, :nested_query_fields
|
29
30
|
|
30
31
|
def_delegators :sobject, :sfdc_client, :build, :table_name, :mappings
|
31
32
|
def_delegators :to_a, :blank?, :present?, :any?, :each, :map, :inspect, :pluck, :each_with_object
|
@@ -36,6 +37,7 @@ module ActiveForce
|
|
36
37
|
@belongs_to_association_mapping = {}
|
37
38
|
super custom_table_name || table_name
|
38
39
|
fields sobject.fields
|
40
|
+
@nested_query_fields = []
|
39
41
|
end
|
40
42
|
|
41
43
|
def to_a
|
@@ -86,8 +88,11 @@ module ActiveForce
|
|
86
88
|
end
|
87
89
|
result
|
88
90
|
else
|
89
|
-
|
90
|
-
|
91
|
+
fields_collection = ActiveForce::SelectBuilder.new(selected_fields, self).parse
|
92
|
+
nested_query_fields.concat(fields_collection[:nested_query_fields]) if fields_collection[:nested_query_fields]
|
93
|
+
return self if fields_collection[:non_nested_query_fields].blank?
|
94
|
+
|
95
|
+
super *fields_collection[:non_nested_query_fields]
|
91
96
|
end
|
92
97
|
end
|
93
98
|
|
@@ -114,7 +119,7 @@ module ActiveForce
|
|
114
119
|
end
|
115
120
|
|
116
121
|
def includes(*relations)
|
117
|
-
includes_query = Association::EagerLoadBuilderForNestedIncludes.build(relations, sobject)
|
122
|
+
includes_query = Association::EagerLoadBuilderForNestedIncludes.build(relations, sobject, nil, nested_query_fields)
|
118
123
|
fields includes_query[:fields]
|
119
124
|
association_mapping.merge!(includes_query[:association_mapping])
|
120
125
|
self
|
@@ -6,18 +6,19 @@ module ActiveForce
|
|
6
6
|
class EagerLoadBuilderForNestedIncludes
|
7
7
|
|
8
8
|
class << self
|
9
|
-
def build(relations, current_sobject, parent_association_field = nil)
|
10
|
-
new(relations, current_sobject, parent_association_field).projections
|
9
|
+
def build(relations, current_sobject, parent_association_field = nil, query_fields = nil)
|
10
|
+
new(relations, current_sobject, parent_association_field, query_fields).projections
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
attr_reader :relations, :current_sobject, :association_mapping, :parent_association_field, :fields
|
14
|
+
attr_reader :relations, :current_sobject, :association_mapping, :parent_association_field, :fields, :query_fields
|
15
15
|
|
16
|
-
def initialize(relations, current_sobject, parent_association_field = nil)
|
16
|
+
def initialize(relations, current_sobject, parent_association_field = nil, query_fields = nil)
|
17
17
|
@relations = [relations].flatten
|
18
18
|
@current_sobject = current_sobject
|
19
19
|
@association_mapping = {}
|
20
20
|
@parent_association_field = parent_association_field
|
21
|
+
@query_fields = query_fields
|
21
22
|
@fields = []
|
22
23
|
end
|
23
24
|
|
@@ -37,10 +38,17 @@ module ActiveForce
|
|
37
38
|
end
|
38
39
|
|
39
40
|
def build_includes(association)
|
40
|
-
fields.concat(EagerLoadProjectionBuilder.build(association, parent_association_field))
|
41
|
+
fields.concat(EagerLoadProjectionBuilder.build(association, parent_association_field, query_fields_for(association)))
|
41
42
|
association_mapping[association.sfdc_association_field.downcase] = association.relation_name
|
42
43
|
end
|
43
44
|
|
45
|
+
def query_fields_for(association)
|
46
|
+
return nil if query_fields.blank?
|
47
|
+
query_fields_with_association = query_fields.find { |nested_field| nested_field[association.relation_name].present? }
|
48
|
+
return nil if query_fields_with_association.blank?
|
49
|
+
query_fields_with_association[association.relation_name].map { |field| association.relation_model.mappings[field] }
|
50
|
+
end
|
51
|
+
|
44
52
|
def build_hash_includes(relation, model = current_sobject, parent_association_field = nil)
|
45
53
|
relation.each do |key, value|
|
46
54
|
association = model.associations[key]
|
@@ -63,10 +71,10 @@ module ActiveForce
|
|
63
71
|
|
64
72
|
def build_relation(association, nested_includes)
|
65
73
|
builder_class = ActiveForce::Association::EagerLoadProjectionBuilder.projection_builder_class(association)
|
66
|
-
projection_builder = builder_class.new(association)
|
74
|
+
projection_builder = builder_class.new(association, nil, query_fields_for(association))
|
67
75
|
sub_query = projection_builder.query_with_association_fields
|
68
76
|
association_mapping[association.sfdc_association_field.downcase] = association.relation_name
|
69
|
-
nested_includes_query = self.class.build(nested_includes, association.relation_model)
|
77
|
+
nested_includes_query = self.class.build(nested_includes, association.relation_model, nil, query_fields)
|
70
78
|
sub_query.fields nested_includes_query[:fields]
|
71
79
|
{ fields: ["(#{sub_query})"], association_mapping: nested_includes_query[:association_mapping] }
|
72
80
|
end
|
@@ -78,7 +86,7 @@ module ActiveForce
|
|
78
86
|
else
|
79
87
|
current_parent_association_field = association.sfdc_association_field
|
80
88
|
end
|
81
|
-
self.class.build(nested_includes, association.relation_model, current_parent_association_field)
|
89
|
+
self.class.build(nested_includes, association.relation_model, current_parent_association_field, query_fields)
|
82
90
|
end
|
83
91
|
end
|
84
92
|
end
|
@@ -3,8 +3,8 @@ module ActiveForce
|
|
3
3
|
class InvalidEagerLoadAssociation < StandardError; end
|
4
4
|
class EagerLoadProjectionBuilder
|
5
5
|
class << self
|
6
|
-
def build(association, parent_association_field = nil)
|
7
|
-
new(association, parent_association_field).projections
|
6
|
+
def build(association, parent_association_field = nil, query_fields = nil)
|
7
|
+
new(association, parent_association_field, query_fields).projections
|
8
8
|
end
|
9
9
|
|
10
10
|
def projection_builder_class(association)
|
@@ -15,26 +15,27 @@ module ActiveForce
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
attr_reader :association, :parent_association_field
|
18
|
+
attr_reader :association, :parent_association_field, :query_fields
|
19
19
|
|
20
|
-
def initialize(association, parent_association_field = nil)
|
20
|
+
def initialize(association, parent_association_field = nil, query_fields = nil)
|
21
21
|
@association = association
|
22
22
|
@parent_association_field = parent_association_field
|
23
|
+
@query_fields = query_fields
|
23
24
|
end
|
24
25
|
|
25
26
|
def projections
|
26
27
|
builder_class = self.class.projection_builder_class(association)
|
27
|
-
builder_class.new(association, parent_association_field).projections
|
28
|
+
builder_class.new(association, parent_association_field, query_fields).projections
|
28
29
|
end
|
29
|
-
|
30
30
|
end
|
31
31
|
|
32
32
|
class AbstractProjectionBuilder
|
33
|
-
attr_reader :association, :parent_association_field
|
33
|
+
attr_reader :association, :parent_association_field, :query_fields
|
34
34
|
|
35
|
-
def initialize(association, parent_association_field = nil)
|
35
|
+
def initialize(association, parent_association_field = nil, query_fields = nil)
|
36
36
|
@association = association
|
37
37
|
@parent_association_field = parent_association_field
|
38
|
+
@query_fields = query_fields
|
38
39
|
end
|
39
40
|
|
40
41
|
def projections
|
@@ -54,8 +55,8 @@ module ActiveForce
|
|
54
55
|
# to be pluralized
|
55
56
|
def query_with_association_fields
|
56
57
|
relationship_name = association.sfdc_association_field
|
57
|
-
|
58
|
-
query.
|
58
|
+
selected_fields = query_fields || association.relation_model.fields
|
59
|
+
query = ActiveQuery.new(association.relation_model, relationship_name).select(*selected_fields)
|
59
60
|
apply_association_scope(query)
|
60
61
|
end
|
61
62
|
end
|
@@ -79,7 +80,8 @@ module ActiveForce
|
|
79
80
|
else
|
80
81
|
association.sfdc_association_field
|
81
82
|
end
|
82
|
-
association.relation_model.fields
|
83
|
+
selected_fields = query_fields || association.relation_model.fields
|
84
|
+
selected_fields.map do |field|
|
83
85
|
"#{ association_field }.#{ field }"
|
84
86
|
end
|
85
87
|
end
|
data/lib/active_force/query.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
module ActiveForce
|
2
|
+
class SelectBuilder
|
3
|
+
|
4
|
+
attr_reader :selected_fields, :nested_query_fields, :non_nested_query_fields, :query
|
5
|
+
|
6
|
+
def initialize(selected_fields, query)
|
7
|
+
@query = query
|
8
|
+
@selected_fields = selected_fields
|
9
|
+
@non_nested_query_fields = []
|
10
|
+
@nested_query_fields = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse
|
14
|
+
selected_fields.each do |field|
|
15
|
+
case field
|
16
|
+
when Symbol
|
17
|
+
non_nested_query_fields << query.mappings[field]
|
18
|
+
when Hash
|
19
|
+
populate_nested_query_fields(field)
|
20
|
+
when String
|
21
|
+
non_nested_query_fields << field
|
22
|
+
end
|
23
|
+
end
|
24
|
+
{non_nested_query_fields: non_nested_query_fields, nested_query_fields: nested_query_fields}
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def populate_nested_query_fields(field)
|
30
|
+
field.each do |key, value|
|
31
|
+
case value
|
32
|
+
when Symbol
|
33
|
+
field[key] = [value]
|
34
|
+
when Hash
|
35
|
+
raise ArgumentError, 'Nested Hash is not supported in select statement, you may wish to use an Array'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
nested_query_fields << field
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/active_force/sobject.rb
CHANGED
@@ -26,14 +26,15 @@ module ActiveForce
|
|
26
26
|
|
27
27
|
define_model_callbacks :build, :create, :update, :save, :destroy
|
28
28
|
|
29
|
-
class_attribute :mappings, :
|
29
|
+
class_attribute :mappings, :table_name_store
|
30
30
|
|
31
31
|
attr_accessor :id, :title
|
32
32
|
|
33
33
|
class << self
|
34
34
|
extend Forwardable
|
35
35
|
def_delegators :query, :not, :or, :where, :first, :last, :all, :find, :find!, :find_by, :find_by!, :sum, :count, :includes, :limit, :order, :select, :none
|
36
|
-
def_delegators :mapping, :table, :
|
36
|
+
def_delegators :mapping, :table, :custom_table?, :mappings
|
37
|
+
alias_method :table_name=, :table_name_store=
|
37
38
|
|
38
39
|
def update(id, attributes)
|
39
40
|
prepare_for_update(id, attributes).update
|
@@ -43,6 +44,10 @@ module ActiveForce
|
|
43
44
|
prepare_for_update(id, attributes).update!
|
44
45
|
end
|
45
46
|
|
47
|
+
def table_name
|
48
|
+
table_name_store || mapping.table_name
|
49
|
+
end
|
50
|
+
|
46
51
|
private
|
47
52
|
|
48
53
|
def prepare_for_update(id, attributes)
|
@@ -65,6 +70,10 @@ module ActiveForce
|
|
65
70
|
@mapping ||= ActiveForce::Mapping.new name
|
66
71
|
end
|
67
72
|
|
73
|
+
def table_name
|
74
|
+
table_name_store || self.class.mapping.table_name
|
75
|
+
end
|
76
|
+
|
68
77
|
def self.fields
|
69
78
|
mapping.sfdc_names
|
70
79
|
end
|
data/lib/active_force/version.rb
CHANGED
@@ -43,6 +43,25 @@ module ActiveForce
|
|
43
43
|
expect(territory.quota.id).to eq "321"
|
44
44
|
end
|
45
45
|
|
46
|
+
context 'when nested select statement' do
|
47
|
+
it 'formulates the correct SOQL query' do
|
48
|
+
soql = Salesforce::Territory.select(:id, :quota_id, quota: :id).includes(:quota).where(id: '123').to_s
|
49
|
+
expect(soql).to eq "SELECT Id, QuotaId, QuotaId.Id FROM Territory WHERE (Id = '123')"
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'errors when correct format is not followed' do
|
53
|
+
expect{Salesforce::Territory.select(:id, :quota_id, quota: {id: :quote}).includes(:quota).where(id: '123').to_s}.to raise_error ArgumentError
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when nested includes statement' do
|
57
|
+
it 'formulates the correct SOQL query' do
|
58
|
+
soql = Comment.select(:post_id, :body, post: [:title, :is_active], blog: :name).includes(post: :blog).to_s
|
59
|
+
|
60
|
+
expect(soql).to eq "SELECT PostId, Body__c, PostId.Title__c, PostId.IsActive, PostId.BlogId.Name FROM Comment__c"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
46
65
|
context 'with namespaced SObjects' do
|
47
66
|
it 'queries the API for the associated record' do
|
48
67
|
soql = Salesforce::Territory.includes(:quota).where(id: '123').to_s
|
@@ -156,6 +175,20 @@ module ActiveForce
|
|
156
175
|
end
|
157
176
|
|
158
177
|
context 'has_many' do
|
178
|
+
context 'when nested select statement' do
|
179
|
+
it 'formulates the correct SOQL query' do
|
180
|
+
soql = Account.select(opportunities: :id).includes(:opportunities).where(id: '123').to_s
|
181
|
+
expect(soql).to eq "SELECT Id, OwnerId, (SELECT Id FROM Opportunities) FROM Account WHERE (Id = '123')"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context 'when normal select with nested includes' do
|
186
|
+
it 'formulates the correct SOQL query' do
|
187
|
+
soql = Blog.select(:id, :link).includes(posts: :comments).to_s
|
188
|
+
expect(soql).to eq "SELECT Id, Link__c, (SELECT Id, Title__c, BlogId, IsActive, (SELECT Id, PostId, PosterId__c, FancyPostId, Body__c FROM Comments__r) FROM Posts__r) FROM Blog__c"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
159
192
|
context 'with standard objects' do
|
160
193
|
it 'formulates the correct SOQL query' do
|
161
194
|
soql = Account.includes(:opportunities).where(id: '123').to_s
|
@@ -294,6 +327,13 @@ module ActiveForce
|
|
294
327
|
end
|
295
328
|
|
296
329
|
context 'has_one' do
|
330
|
+
context 'when nested select statement is present' do
|
331
|
+
it 'formulates the correct SOQL query' do
|
332
|
+
soql = ClubMember.select(:name, :email, membership: :type).includes(:membership).to_s
|
333
|
+
expect(soql).to eq "SELECT Name, Email, (SELECT Type FROM Membership__r) FROM ClubMember__c"
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
297
337
|
context 'when assocation has a scope' do
|
298
338
|
it 'formulates the correct SOQL query with the scope applied' do
|
299
339
|
soql = Post.includes(:last_comment).where(id: '1234').to_s
|
@@ -375,6 +375,20 @@ describe ActiveForce::SObject do
|
|
375
375
|
end
|
376
376
|
end
|
377
377
|
|
378
|
+
describe '.table_name' do
|
379
|
+
|
380
|
+
context 'when no explicit table name is set' do
|
381
|
+
it 'derives the table name from the class name' do
|
382
|
+
expect(Whizbang.table_name).to eq('Whizbang__c')
|
383
|
+
end
|
384
|
+
end
|
385
|
+
context 'when explicit table name is set' do
|
386
|
+
it 'returns the explicit table name' do
|
387
|
+
expect(Whizbang2.table_name).to eq('Whiz_bang2__c')
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
378
392
|
describe '.sum' do
|
379
393
|
let(:response) { [Restforce::Mash.new(expr0: 22)] }
|
380
394
|
|
data/spec/spec_helper.rb
CHANGED
data/spec/support/whizbang.rb
CHANGED
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.
|
4
|
+
version: 0.25.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eloy Espinaco
|
@@ -11,34 +11,34 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2025-08-07 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: activemodel
|
18
18
|
requirement: !ruby/object:Gem::Requirement
|
19
19
|
requirements:
|
20
|
-
- - "
|
20
|
+
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '7.0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- - "
|
27
|
+
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '7.0'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: activesupport
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
requirements:
|
34
|
-
- - "
|
34
|
+
- - ">="
|
35
35
|
- !ruby/object:Gem::Version
|
36
36
|
version: '7.0'
|
37
37
|
type: :runtime
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
|
-
- - "
|
41
|
+
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: '7.0'
|
44
44
|
- !ruby/object:Gem::Dependency
|
@@ -125,6 +125,20 @@ dependencies:
|
|
125
125
|
- - ">="
|
126
126
|
- !ruby/object:Gem::Version
|
127
127
|
version: '0'
|
128
|
+
- !ruby/object:Gem::Dependency
|
129
|
+
name: simplecov-cobertura
|
130
|
+
requirement: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - ">="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
type: :development
|
136
|
+
prerelease: false
|
137
|
+
version_requirements: !ruby/object:Gem::Requirement
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
128
142
|
description: Use SalesForce as an ActiveModel
|
129
143
|
email: eloyesp@gmail.com
|
130
144
|
executables: []
|
@@ -134,7 +148,6 @@ files:
|
|
134
148
|
- ".circleci/config.yml"
|
135
149
|
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
136
150
|
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
137
|
-
- ".github/workflows"
|
138
151
|
- ".gitignore"
|
139
152
|
- ".mailmap"
|
140
153
|
- ".rspec"
|
@@ -163,6 +176,7 @@ files:
|
|
163
176
|
- lib/active_force/field.rb
|
164
177
|
- lib/active_force/mapping.rb
|
165
178
|
- lib/active_force/query.rb
|
179
|
+
- lib/active_force/select_builder.rb
|
166
180
|
- lib/active_force/sobject.rb
|
167
181
|
- lib/active_force/standard_types.rb
|
168
182
|
- lib/active_force/table.rb
|
@@ -219,7 +233,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
219
233
|
- !ruby/object:Gem::Version
|
220
234
|
version: '0'
|
221
235
|
requirements: []
|
222
|
-
rubygems_version: 3.
|
236
|
+
rubygems_version: 3.4.10
|
223
237
|
signing_key:
|
224
238
|
specification_version: 4
|
225
239
|
summary: Help you implement models persisting on Sales Force within Rails using RESTForce
|
data/.github/workflows
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
on:
|
2
|
-
pull_request:
|
3
|
-
types: [opened, reopened, synchronize]
|
4
|
-
pull_request_review_comment:
|
5
|
-
types: [created, edited, deleted]
|
6
|
-
|
7
|
-
name: Metomic Scan
|
8
|
-
|
9
|
-
jobs:
|
10
|
-
scan-secrets:
|
11
|
-
name: Scan For Secrets
|
12
|
-
runs-on: ubuntu-latest
|
13
|
-
steps:
|
14
|
-
- name: checkout-repo
|
15
|
-
uses: actions/checkout@v3
|
16
|
-
with:
|
17
|
-
ref: ${{ github.event.pull_request.head.sha }}
|
18
|
-
|
19
|
-
- name: authenticate-with-metomic
|
20
|
-
id: authenticate
|
21
|
-
continue-on-error: ${{ vars.METOMIC_FAIL_ON_CONNECTION_ERROR != 'TRUE' }}
|
22
|
-
run: |
|
23
|
-
curl -s --location --request GET '${{ vars.METOMIC_INTEGRATION_ENDPOINT }}/token' --header 'X-API-Key: ${{ secrets.METOMIC_API_TOKEN }}' -o .metomic_token.json
|
24
|
-
echo METOMIC_ACCESS_TOKEN=$(cat .metomic_token.json | jq -r -c '.accessToken') >> $GITHUB_OUTPUT
|
25
|
-
PASS=$(cat .metomic_token.json | jq -r -c '.accessToken // empty')
|
26
|
-
if [ -z "$PASS" ]; then
|
27
|
-
cat .metomic_token.json
|
28
|
-
echo ""
|
29
|
-
echo "FAIL: failed to fetch auth token from Metomic. Ensure required organisation variables / secrets are set correctly. METOMIC_INTEGRATION_ENDPOINT, METOMIC_API_TOKEN"
|
30
|
-
echo "The correct values for these variables are available from the installations page of the Metomic dashboard"
|
31
|
-
exit 1
|
32
|
-
fi
|
33
|
-
|
34
|
-
- name: checkout-metomic-action
|
35
|
-
id: checkout
|
36
|
-
uses: actions/checkout@v3
|
37
|
-
if: ${{ steps.authenticate.outcome == 'success' }}
|
38
|
-
continue-on-error: ${{ vars.METOMIC_FAIL_ON_CONNECTION_ERROR != 'TRUE' }}
|
39
|
-
with:
|
40
|
-
repository: metomic/metomic-github-integration-action.git
|
41
|
-
path: "./.metomic"
|
42
|
-
ref: "main"
|
43
|
-
token: ${{ steps.authenticate.outputs.METOMIC_ACCESS_TOKEN }}
|
44
|
-
|
45
|
-
- name: scan
|
46
|
-
uses: ./.metomic/.github/actions/scan-secrets
|
47
|
-
if: ${{ steps.authenticate.outputs.METOMIC_ACCESS_TOKEN && steps.checkout.outcome == 'success' }}
|
48
|
-
with:
|
49
|
-
metomic_endpoint: ${{ vars.METOMIC_INTEGRATION_ENDPOINT }}
|
50
|
-
metomic_api_token: ${{ secrets.METOMIC_API_TOKEN }}
|
51
|
-
head_ref: ${{ github.event.pull_request.head.sha }}
|