SFDO-API 0.1.9 → 1.0.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
  SHA1:
3
- metadata.gz: c852c0ed4fb33d2702921867b16bfd991e8eaf28
4
- data.tar.gz: ee15a382213300a9d96f78c91987048e208644bb
3
+ metadata.gz: ad083f17c296ab1f98d9ccefeea3b04b594daa98
4
+ data.tar.gz: 465ec5467fcb682148573f07d531b2f57800d8d3
5
5
  SHA512:
6
- metadata.gz: bbae2077803087383d951e693b252da0196c4a62d1624266c466812a067bdc77da025419a2d9fae2857b3f8c899e9ad5dccbfa8f99f667b711d9efe8484e8ded
7
- data.tar.gz: e4cef1d73bf90664b90106687008a824ad3225332d993431d3237c25a8eb70dc32e6e6cde5997142ceb4863910de6b8dacb1abdf71b34851ecfc4194816255a4
6
+ metadata.gz: d81c512b1ee4c35ec0b146da5cd1b565d3edbcb253cb47ac92c302036979346de9116f65e00f8157e1842943d7e8b1bc0259d6f12abf9719ad9223d1e8db08f8
7
+ data.tar.gz: 30225adca39ab25f808db5e74f6605025997aef2ca8ad341bf71d63df0bbdd1ea3fb0068188c45cf02f39cd28ec35e3f50f7fa96bd2e6bfbd09bde9673016729
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SFDO::API
2
2
 
3
- SFDO-API is a convenient way to use the Salesforce API to manipulate objects in a target org. SFDO-API was intended orginally to
3
+ SFDO-API is a convenient way to use the Salesforce API to manipulate objects and fields on objects in a target org. SFDO-API was intended orginally to
4
4
  facilitate the sharing of common API calls across multiple source repositories, but the project is evolving to provide powerful
5
5
  tools for handiling SF objects, like support for managed and unmanaged namespaces, multiple namespaces in an org, etc.
6
6
 
@@ -58,6 +58,13 @@ addressing "npsp__General_Accounting_Unit__c" use plain "General_Accounting_Unit
58
58
  gaus = select_api 'select Id from General_Accounting_Unit'
59
59
  ```
60
60
 
61
+ Likewise, when addressing custom fields, leave off any namespace values for the fields involved
62
+
63
+ ```ruby
64
+ #@relationshiop_id = create 'Relationship', npe4__Contact__c: contact, npe4__RelatedContact__c: related_contact
65
+ @relationshiop_id = create 'Relationship', Contact: contact, RelatedContact: related_contact
66
+ ```
67
+
61
68
  To delete a single instance of an object for which you have the Id value
62
69
 
63
70
  ```ruby
@@ -111,7 +118,17 @@ puts gaus.inspect
111
118
  end
112
119
  ```
113
120
 
114
- ### SELECT and UPDATE actions with custom objects
121
+ Likewise when using custom fields on any object, do not use any namespace value at the front of the object name, and leave off any
122
+ custom trailer values like "__c" or "__r, SFDO-API handles that for you. Instead of addressing
123
+ "npsp__General_Accounting_Unit__c" use plain "General_Accounting_Unit" instead, and instead of the field
124
+ "npe01__Account_Processor__c" use just "Account_Processor"
125
+
126
+ ```ruby
127
+ #@contact_id = create 'Contact', LastName: contact_name, MailingCity: 'hhmailingcity', npo02__Household__c: @hh_obj_id
128
+ @contact_id = create 'Contact', LastName: contact_name, MailingCity: 'hhmailingcity', Household: @hh_obj_id
129
+ ```
130
+
131
+ ### SELECT and UPDATE actions with custom objects and custom fields
115
132
 
116
133
  Use the select_api() and update_api() methods without namespaces or trailing characters.
117
134
 
@@ -123,15 +140,13 @@ to change, then call update_api() with the altered version of the restforce obje
123
140
  api_client do
124
141
  acc_id = select_api 'select Id from Contacts_And_Orgs_Settings'
125
142
  acc = acc_id.first
126
- acc.npe01__Account_Processor__c = to_value
143
+ #acc.npe01__Account_Processor__c = to_value
144
+ acc.Account_Processor = to_value
127
145
  update_api(acc)
128
146
  end
129
147
  end
130
148
  ```
131
149
 
132
- Note that at this time, *fields* on objects with custom namespaces are not discovered automatically at runtime.
133
- See TODO section below:
134
-
135
150
  ### Using objects where local override changes required fields
136
151
 
137
152
  Note that ISVs may override required fields on standard Salesforce objects, and these may be needed for SFDO-API to work properly
@@ -146,9 +161,9 @@ Note that ISVs may override required fields on standard Salesforce objects, and
146
161
 
147
162
  ### TODO
148
163
 
149
- Fields on namespaced object may be namespaced themselves. SFDO-API does not handle this case yet.
150
-
151
- Custom fields on standard Salesforce objects may have namespaces. SFDO-API does not handle such fields yet.
164
+ At this time SFDO-API does not accept custom fields that are properly named. For example if a field is in fact named
165
+ "npe01__Account_Processor__c" that field must be addressed as "Account_Processor" and will not function properly if the
166
+ calling code uses the properly namespaced value of the field.
152
167
 
153
168
  ## Development
154
169
 
@@ -3,7 +3,6 @@ lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'SFDO/API/version'
5
5
 
6
-
7
6
  Gem::Specification.new do |spec|
8
7
  spec.name = "SFDO-API"
9
8
  spec.version = SFDO::API::VERSION
@@ -2,20 +2,32 @@ require 'SFDO/API/version'
2
2
  require 'pry'
3
3
 
4
4
  module SfdoAPI
5
-
6
5
  def api_client
7
- @api_client ||= Restforce.new api_version: '32.0',
8
- refresh_token: ENV['SF_REFRESH_TOKEN'],
9
- client_id: ENV['SF_CLIENT_KEY'],
10
- client_secret: ENV['SF_CLIENT_SECRET']
11
- yield
6
+ if ENV['SF_ACCESS_TOKEN'] && ENV['SF_INSTANCE_URL']
7
+ @api_client ||= Restforce.new(oauth_token: ENV['SF_ACCESS_TOKEN'],
8
+ instance_url: ENV['SF_INSTANCE_URL'],
9
+ api_version: '32.0')
10
+ yield
11
+ else
12
+ @api_client ||= Restforce.new api_version: '32.0',
13
+ refresh_token: ENV['SF_REFRESH_TOKEN'],
14
+ client_id: ENV['SF_CLIENT_KEY'],
15
+ client_secret: ENV['SF_CLIENT_SECRET']
16
+ yield
17
+ end
12
18
  end
13
19
 
14
20
  def create(type, obj_hash)
21
+ true_fields = {}
22
+
15
23
  type = true_object_name(type)
24
+ obj_mash = Hashie::Mash.new obj_hash
25
+
26
+ obj_mash.map { |x, y| true_fields.store(true_field_name(x, type), y) }
27
+
16
28
  if is_valid_obj_hash?(type, obj_hash, @fields_acceptibly_nil)
17
29
  obj_id = api_client do
18
- @api_client.create! type, obj_hash
30
+ @api_client.create! type, true_fields
19
31
  end
20
32
  end
21
33
  obj_id
@@ -28,26 +40,41 @@ module SfdoAPI
28
40
  obj_name = query[/(?<=from )(.*)$/i]
29
41
  end
30
42
 
43
+ # GET TRUE OBJECT NAME BEFORE GETTING TRUE FIELD NAMES
31
44
  real_obj_name = true_object_name(obj_name)
32
45
 
33
- query = query.gsub(obj_name, real_obj_name)
46
+ # REMOVE NEWLINES IF ANY
47
+ query = query.gsub(/\n/, ' ')
48
+ # REMOVE EXTRA SPACES
49
+ query = query.gsub(/\s{2,}/, ' ')
50
+ # GET FIELDS ONLY
51
+ fields_array = query.split(' from ').first.scan /\w*\s*\s([a-zA-Z0-9_]*)/
34
52
 
35
- results = api_client do
36
- @api_client.query query
37
- end
53
+ fields_array.each do |field|
54
+ real_field = true_field_name(field[0], real_obj_name)
55
+
56
+ if obj_name != real_obj_name
57
+ query = query.gsub(/\b#{obj_name}\b/, real_obj_name)
58
+ end
59
+
60
+ if field[0] != real_field
61
+ query = query.gsub(field[0], real_field)
62
+ end
63
+ end
64
+
65
+ results = api_client do
66
+ @api_client.query query
67
+ end
38
68
  results
39
69
  end
40
70
 
41
71
  def is_valid_obj_hash?(object_name, obj_hash, fields_acceptibly_nil)
42
- #TODO Take incoming field names;parse out namespace/__c values; get true namespace for fields also
43
- #TODO We do it from here because this is the only place we know about fields on objects
44
- required_fields = get_object_describe(object_name).map(&:fieldName)
72
+ required_fields = get_required_fields_on_object(object_name).map(&:fieldName)
45
73
  valid = true
46
74
  required_fields.each do |f|
47
-
48
75
  valid = false if (!obj_hash.key? f.to_sym) && (begin
49
76
  !fields_acceptibly_nil[object_name].contains? f
50
- puts 'This field must be populated in order to create this object in this environment: ' + f.inspect
77
+ puts 'This field must be populated in order to create this object in this environment: ' + f.inspect
51
78
  rescue
52
79
  false
53
80
  end)
@@ -55,13 +82,13 @@ module SfdoAPI
55
82
  valid
56
83
  end
57
84
 
58
- def org_describe()
85
+ def org_describe
59
86
  if @org_description.nil? || !@org_description.respond_to?(:contains)
60
87
  @org_description = api_client do
61
88
  @api_client.describe
62
89
  end
63
90
  end
64
- return @org_description
91
+ @org_description
65
92
  end
66
93
 
67
94
  def prefix_to_name
@@ -71,33 +98,61 @@ module SfdoAPI
71
98
  @prefix_to_name.store(z.keyPrefix, z.name)
72
99
  end
73
100
  end
74
- return @prefix_to_name
101
+ @prefix_to_name
75
102
  end
76
103
 
77
- def true_object_name(handle) #either an ID or a string name
78
- handle = (handle.end_with?("__c") || handle.end_with?("__r")) ? handle[0...-3] : handle
104
+ def true_field_name(field, obj)
105
+ # See if we've done an object describe on the object
106
+ # If so, return the fields for the object
107
+ # Otherwise do an object describe, save the object description and return the fields with their real names
108
+ @full_describe = {} if @full_describe.nil?
109
+
110
+ if @full_describe[obj].nil?
111
+ object_description = get_object_describe(obj)
112
+ fields = object_description.map do |f|
113
+
114
+ # MANAGED CODE
115
+ if f.fieldName.match /.*__.*__.*/
116
+ substituted = f.fieldName.gsub(/\A.*?__/, '').gsub(/__c\z/, '')
117
+ else
118
+ # UNMANAGED CODE
119
+ substituted = f.fieldName.gsub(/__c\z/, '')
120
+ end
121
+
122
+ { substituted => f.fieldName }
123
+ end
124
+ @full_describe[obj] = fields.reduce({}, :merge)
125
+ end
126
+
127
+ # RETURN THE REAL NAME FROM OUR HASH OF INPUT TO REAL NAMES
128
+ @full_describe[obj][field]
129
+ end
130
+
131
+ def true_object_name(handle) # either an ID or a string name
132
+ # handle = (handle.end_with?("__c") || handle.end_with?("__r")) ? handle[0...-3] : handle
133
+ handle.end_with?('__c', '__r') ? handle[0...-3] : handle
79
134
  from_id = prefix_to_name[handle[0..2]]
80
135
  from_name = obj_names_without_custom_additions[handle]
81
136
  if !from_name.nil? || !from_id.nil?
82
137
  return from_name if from_id.nil?
83
138
  return from_id if from_name.nil?
84
139
  end
85
- return 'Unable to find object. Be sure to call SFDO-API without preceding namespace or following __c or __r'
140
+ 'Unable to find object. Be sure to call SFDO-API without preceding namespace or following __c or __r'
86
141
  end
87
142
 
88
143
  def obj_names_without_custom_additions
89
144
  if @obj_names_without_custom_additions.nil? || !@obj_names_without_custom_additions.respond_to?(:contains)
90
145
  @obj_names_without_custom_additions = {}
91
146
  org_describe.each do |z|
92
- tmp_var = z.name.split "__"
93
- save = ""
147
+ tmp_var = z.name.split '__'
148
+ save = ''
94
149
  case tmp_var.size
95
- when 2
96
- save = tmp_var.first
97
- when 3
98
- save = tmp_var[1]
99
- else
100
- save = tmp_var.last
150
+ when 2
151
+ save = tmp_var.first
152
+ when 3
153
+ save = tmp_var[1]
154
+ else
155
+ save = tmp_var.last
101
156
  end
102
157
  @obj_names_without_custom_additions.store(save, z.name)
103
158
  end
@@ -105,23 +160,33 @@ module SfdoAPI
105
160
  @obj_names_without_custom_additions
106
161
  end
107
162
 
163
+ def get_required_fields_on_object(obj_name)
164
+ @object_fields = {} if @object_fields.nil?
165
+
166
+ if @object_fields[obj_name].nil?
167
+ @object_fields[obj_name] = get_object_describe(obj_name)
168
+ end
169
+
170
+ @object_fields[obj_name].select(&:required)
171
+ end
172
+
108
173
  def get_object_describe(object_name)
109
174
  api_client do
110
175
  @description = @api_client.get("/services/data/v35.0/sobjects/#{object_name}/describe")
111
-
112
176
  describeobject = Hashie::Mash.new(@description.body)
113
177
 
114
178
  required = describeobject.fields.map do |x|
115
179
  Hashie::Mash.new(
116
- fieldName: x.name,
117
- required: (!x.nillable && !x.defaultedOnCreate),
118
- default: x.defaultValue)
180
+ fieldName: x.name,
181
+ required: (!x.nillable && !x.defaultedOnCreate),
182
+ default: x.defaultValue
183
+ )
119
184
  end
120
- required.select(&:required)
185
+ return required
121
186
  end
122
187
  end
123
188
 
124
- def delete(type, obj_id)
189
+ def delete(obj_id)
125
190
  delete_by_id(obj_id)
126
191
  end
127
192
 
@@ -148,19 +213,18 @@ module SfdoAPI
148
213
  obj_type = breakdown.last.capitalize
149
214
 
150
215
  case method_called.to_s
151
- when /^delete_all_/
152
- delete_all *args
153
- when /^delete_one/
154
- delete obj_type, *args
155
- when /^create_/
156
- create obj_type, *args
157
- when /^select_api/
158
- select_api *args
159
- else
160
- super.method_missing
216
+ when /^delete_all_/
217
+ delete_all *args
218
+ when /^delete_one/
219
+ delete obj_type, *args
220
+ when /^create_/
221
+ create obj_type, *args
222
+ when /^select_api/
223
+ select_api *args
224
+ else
225
+ super.method_missing
161
226
  end
162
227
  end
163
-
164
228
  end
165
229
  # INCLUDE HERE RATHER THAN IN THE PRODUCT-SPECIFIC CODE USING THIS GEM
166
230
  include SfdoAPI
@@ -1,5 +1,5 @@
1
1
  module SFDO
2
2
  module API
3
- VERSION = "0.1.9"
3
+ VERSION = "1.0.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: SFDO-API
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris McMahon
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2016-12-01 00:00:00.000000000 Z
12
+ date: 2017-02-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler