sf_cli 0.0.3 → 0.0.5

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -0
  3. data/README.rdoc +30 -8
  4. data/lib/sf_cli/sf/core/base.rb +80 -0
  5. data/lib/sf_cli/sf/data/bulk_result_v2.rb +77 -0
  6. data/lib/sf_cli/sf/data/core.rb +39 -0
  7. data/lib/sf_cli/sf/data/create_record.rb +30 -0
  8. data/lib/sf_cli/sf/data/delete_bulk.rb +47 -0
  9. data/lib/sf_cli/sf/data/delete_record.rb +33 -0
  10. data/lib/sf_cli/sf/data/delete_resume.rb +47 -0
  11. data/lib/sf_cli/sf/data/get_record.rb +42 -0
  12. data/lib/sf_cli/sf/data/helper_methods.rb +47 -0
  13. data/lib/sf_cli/sf/data/query.rb +120 -0
  14. data/lib/sf_cli/sf/data/query_helper.rb +57 -0
  15. data/lib/sf_cli/sf/data/resume.rb +87 -0
  16. data/lib/sf_cli/sf/data/search.rb +50 -0
  17. data/lib/sf_cli/sf/data/update_record.rb +38 -0
  18. data/lib/sf_cli/sf/data/upsert_bulk.rb +50 -0
  19. data/lib/sf_cli/sf/data/upsert_resume.rb +47 -0
  20. data/lib/sf_cli/sf/main.rb +31 -0
  21. data/lib/sf_cli/sf/model/class_definition.rb +112 -0
  22. data/lib/sf_cli/sf/model/generator.rb +27 -0
  23. data/lib/sf_cli/sf/model/schema.rb +33 -0
  24. data/lib/sf_cli/sf/model.rb +21 -0
  25. data/lib/sf_cli/sf/org/core.rb +23 -0
  26. data/lib/sf_cli/sf/org/display.rb +41 -0
  27. data/lib/sf_cli/sf/org/list.rb +67 -0
  28. data/lib/sf_cli/sf/org/login.rb +64 -0
  29. data/lib/sf_cli/sf/project/core.rb +83 -0
  30. data/lib/sf_cli/sf/sobject/core.rb +50 -0
  31. data/lib/sf_cli.rb +19 -1
  32. metadata +38 -15
  33. data/lib/sf_cli/sf/base.rb +0 -34
  34. data/lib/sf_cli/sf/data.rb +0 -148
  35. data/lib/sf_cli/sf/org.rb +0 -49
  36. data/lib/sf_cli/sf/project.rb +0 -68
  37. data/lib/sf_cli/sf/sobject.rb +0 -41
  38. data/lib/sf_cli/sf.rb +0 -87
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d070d17a818ef2dd2030a026e1e3b14a284eb1e4ce1bab9ed46c8f5811c2169
4
- data.tar.gz: aa7aafc17f57d6d9df71e6969caad6c756965cfce76ca5583acd73799366b34c
3
+ metadata.gz: c53d056727e589cb48d79aced7900a9419015ad0840e59b5f4d25361a31468ad
4
+ data.tar.gz: 491d45e9ce3907f931d07526eb37f9698e8c5b4cd95ffb3f38317244d99ea656
5
5
  SHA512:
6
- metadata.gz: ddfd91e3ddd1573938d9dbb9c27749eb8054475cee62d5565222f75ad2867fe1abf3dc3c5cc48a452a79991971532f89b233ddf1db491a83b9f28348fdd53eb0
7
- data.tar.gz: 9df1154ec04b5acefddc469429163feed1ee432abd517048b0915d046c29d9d30a5e097153aa50a5774085720f91c68f86cda484ada9d667a6140cd15bcbe6bb
6
+ metadata.gz: a49220a708a8cab60b8ae22f09b4ac805c6b405c3ae0821809012d0cb4d3b34bfd66f69a3429ae4ed70799a0a6cd793c9edcd52e71b2811aaf7a887bdb8db075
7
+ data.tar.gz: dc8d5efe8ea8001212d448ca71fe874b61625960a6daea6163d459d9603c0d5ccbbf1b8c4795694495e4b1b963100113dd02e9dba56160322e3ab27ebcada2b3
data/CHANGELOG.md ADDED
@@ -0,0 +1,49 @@
1
+ ## 0.0.5 - 2024-09-08
2
+ - target CLI version is changed: from 2.54.6 to 2.56.7
3
+ - sf data:
4
+ - add `--bulk` option to query
5
+ - add query resume
6
+ - add upsert bulk
7
+ - add upsert resume
8
+ - add delete bulk
9
+ - add delete resume
10
+ - add resume
11
+ - add search
12
+ - sf org:
13
+ - add list
14
+ - add login access-token
15
+ - add `--browser` option to login web
16
+
17
+ ## 0.0.4 - 2024-09-02
18
+ - breaking change:
19
+ - Sf class doesn't exist anymore. You can not write like `sf = SfCli::Sf.new`. Instead of that, global `sf` method is introduced. You can directly type like `sf.org.display`, which is as almost same usability as the original command.
20
+ - sf data query:
21
+ - support child-parent relationship
22
+ - support parent-children relationship
23
+ - add `--result-format` option
24
+ - auto generation of \Object Model (experimental)
25
+ - generates SF \Object Classes automatically
26
+ - relationship is supported
27
+
28
+ ## 0.0.3 - 2024-08-25
29
+ add command operations:
30
+
31
+ - sf data get record
32
+ - sf data create record
33
+ - sf data update record
34
+ - sf data delete record
35
+
36
+ ## 0.0.2 - 2024-08-18
37
+ this version up was made by mistake.
38
+ nothing was changed.
39
+
40
+ ## 0.0.1 - 2024-08-18
41
+ support some command operations:
42
+
43
+ - sf org login web
44
+ - sf display
45
+ - sf data query
46
+ - sf sobject describe
47
+ - sf sobject list
48
+ - sf project generate
49
+ - sf project generate manifest
data/README.rdoc CHANGED
@@ -2,12 +2,12 @@
2
2
  https://badge.fury.io/rb/sf_cli.png
3
3
 
4
4
  This is a class library for introducing {Salesforce CLI}[https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_top.htm] to Ruby scripting.<br>
5
- It is designed to be similar usability to the command line interface.<br>
5
+ It is designed to be similar usability to the original command.<br>
6
6
  Currently only *sf* command is the target of development.
7
7
 
8
8
  == prerequisite
9
9
  Salesforce CLI must be installed.<br>
10
- As of as of August in 2024, ver.2.54.6 is the development target.
10
+ As of as of September in 2024, ver.2.56.7 is the development target.
11
11
 
12
12
  == install
13
13
  === Rubygem
@@ -21,30 +21,52 @@ then,
21
21
  $ bundle install
22
22
 
23
23
  == Examples
24
+ === Since 0.0.4
25
+ require 'sf_cli'
26
+
27
+ # login to org
28
+ sf.org.login_web
29
+
30
+ # get records
31
+ sf.data.query 'SELECT Id, Name FROM Account LIMIT 1' # => [{Id: "abc", Name: "account name"}]
32
+
33
+ # generate a Salesforce DX project
34
+ sf.project.generate 'MyProject'
35
+
36
+ === Before 0.0.3
24
37
  require 'sf_cli/sf'
25
38
 
26
39
  sf = SfCli::Sf.new
27
40
 
28
41
  # login to org
29
42
  sf.org.login_web
30
- sf.org.login_web target_org: :dev # name an alias to the org, which you're going to log in, for later use. This is needed when you don't use the default org.
31
43
 
32
44
  # get Account records
33
45
  sf.data.query 'SELECT Id, Name FROM Account LIMIT 3' # => returns an array containing 3 records
34
46
 
35
- Account = Struct.new(:Id, :Name)
36
- sf.data.query('SELECT Id, Name From Account Limit 3', model_class: Account) # returns an array of Account struct object
37
-
38
47
  # generate a Salesforce DX project
39
48
  sf.project.generate 'MyProject'
40
49
 
50
+ == \Object Model support (experimental, since 0.0.4)
51
+ require 'sf_cli'
52
+ require 'sf_cli/sf/model'
53
+
54
+ # generates Model Class for Contact and Account
55
+ SfCli::Sf::Model.generate %w[Contact Account]
56
+
57
+ c = Contact.new(:Name => "John Smith")
58
+ c.Name # => "John Smith"
41
59
 
42
- For more command details, see {Salesforce CLI Command Reference}[https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_top.htm]
60
+ rows = sf.data.query 'SELECT Id, Name, Account.Name From Contact Limit 3', model_class: Contact
61
+ rows.size # => 3
62
+ rows.first.Name # => Name of the Contact
63
+ rows.first.Account.Name # => Name of the Account
43
64
 
44
65
  == Documents
66
+ The following steps generate *doc* directory, which all documents are generated in.
45
67
  $ git clone https://github.com/tmkw/sf_cli.git
46
68
  $ cd sf_cli
47
69
  $ bundle install
48
70
  $ bundle exec rake rdoc
49
71
 
50
- This generates the documents in doc directory.
72
+ *Or*, you can read the same documents online at {rubygems.org}[https://rubygems.org/gems/sf_cli]
@@ -0,0 +1,80 @@
1
+ module SfCli
2
+ module Sf
3
+ module Core
4
+ module Base
5
+ attr_reader :varbose
6
+
7
+ private
8
+
9
+ def exec(action, flags: {}, switches: {}, redirection: nil, raw_output: false, format: :json) # :doc:
10
+ cmd = %|sf #{category} #{action}#{as_flag_options(flags)}#{as_switch_options(switches, format)}#{redirect redirection}|
11
+ puts cmd if varbose
12
+
13
+ return `#{cmd}` if raw_output
14
+
15
+ json = JSON.parse `#{cmd}`
16
+ puts json if varbose
17
+ raise StandardError.new(json['message']) if json['status'] != 0
18
+
19
+ json
20
+ end
21
+
22
+ def category
23
+ self.class.name.split('::')[-2].downcase
24
+ end
25
+
26
+ def field_value_pairs(hash)
27
+ return nil if hash.nil?
28
+ return nil if hash.empty?
29
+
30
+ hash.each_with_object([]) do|(k,v), arr|
31
+ value = v.instance_of?(String) ? %|'#{v}'| : v
32
+ arr << %(#{k}=#{value})
33
+ end
34
+ .join(' ')
35
+ end
36
+
37
+ def as_flag_options(hash)
38
+ flag_options = hash.map{|k,v| flag k, v}.reject(&:nil?).join(' ')
39
+ flag_options = ' ' + flag_options unless flag_options.empty?
40
+
41
+ flag_options
42
+ end
43
+
44
+ def as_switch_options(hash, format)
45
+ if format.to_sym == :json
46
+ ' ' + {json: true}.merge(hash).each_with_object([]){|(k,v), arr| arr << %(--#{k}) if v}.join(' ')
47
+ else
48
+ return '' if hash.empty?
49
+ hash.each_with_object([]){|(k,v), arr| arr << %(--#{k}) if v}.join(' ')
50
+ end
51
+ end
52
+
53
+ def flag(name, arg)
54
+ arg ? %(--#{name} #{arg}) : nil
55
+ end
56
+
57
+ def os
58
+ @os ||= ENV['OS']
59
+ end
60
+
61
+ def redirect(option)
62
+ case option
63
+ when :null_stderr
64
+ null_stderr_redirection
65
+ else
66
+ end
67
+ end
68
+
69
+ def null_stderr_redirection
70
+ @null_stderr_redirection ||=
71
+ if os.eql?('Windows_NT')
72
+ ' 2>nul'
73
+ else
74
+ ' 2> /dev/null'
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,77 @@
1
+ module SfCli
2
+ module Sf
3
+ module Data
4
+ #
5
+ # Bulk Job information.
6
+ #
7
+ # You can check the job status using the following method:
8
+ # - opened?
9
+ # - upload_completed?
10
+ # - in_progress?
11
+ # - completed?
12
+ # ==== example:
13
+ # result = sf.data.delete_resume job_id: jobinfo.id
14
+ # puts 'yey!' if result.job_info.completed? # the job has completed
15
+ #
16
+ # For more details, see {the guide document}[https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/bulk_api_2_job_states.htm]
17
+ #
18
+ JobInfo = Struct.new(
19
+ :id,
20
+ :operation,
21
+ :object,
22
+ :createdById,
23
+ :createdDate,
24
+ :systemModstamp,
25
+ :state,
26
+ :externalIdFieldName,
27
+ :concurrencyMode,
28
+ :contentType,
29
+ :apiVersion,
30
+ :jobType,
31
+ :lineEnding,
32
+ :columnDelimiter,
33
+ :numberRecordsProcessed,
34
+ :numberRecordsFailed,
35
+ :retries,
36
+ :totalProcessingTime,
37
+ :apiActiveProcessingTime,
38
+ :apexProcessingTime,
39
+ :isPkChunkingSupported
40
+ ) do
41
+ def opened?
42
+ state == 'Open'
43
+ end
44
+
45
+ def upload_completed?
46
+ state == 'UploadComplete'
47
+ end
48
+
49
+ def in_progress?
50
+ state == 'InProgress'
51
+ end
52
+
53
+ def completed?
54
+ state == 'JobComplete'
55
+ end
56
+
57
+ def failed?
58
+ state == 'Failed'
59
+ end
60
+
61
+ def aborted?
62
+ state == 'Aborted'
63
+ end
64
+ end
65
+
66
+ #
67
+ # Records processed by Bulk API
68
+ #
69
+ BulkRecordsV2 = Struct.new(:successfulResults, :failedResults, :unprocessedRecords)
70
+
71
+ #
72
+ # Bulk Result information that contains JobInfo and BulkRecordsV2
73
+ #
74
+ BulkResultV2 = Struct.new(:job_info, :records)
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,39 @@
1
+ require_relative '../core/base'
2
+ require_relative './query'
3
+ require_relative './get_record'
4
+ require_relative './update_record'
5
+ require_relative './create_record'
6
+ require_relative './delete_record'
7
+ require_relative './delete_bulk'
8
+ require_relative './delete_resume'
9
+ require_relative './upsert_bulk'
10
+ require_relative './upsert_resume'
11
+ require_relative './resume'
12
+ require_relative './search'
13
+
14
+ module SfCli
15
+ module Sf
16
+ module Data
17
+ #
18
+ # ==== description
19
+ # The class representing *sf* *data*
20
+ #
21
+ # https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_data_commands_unified.htm
22
+ #
23
+ class Core
24
+ include ::SfCli::Sf::Core::Base
25
+ include Query
26
+ include GetRecord
27
+ include UpdateRecord
28
+ include CreateRecord
29
+ include DeleteRecord
30
+ include DeleteBulk
31
+ include DeleteResume
32
+ include UpsertBulk
33
+ include UpsertResume
34
+ include Resume
35
+ include Search
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,30 @@
1
+ module SfCli::Sf::Data
2
+ module CreateRecord
3
+ # create a object record.
4
+ #
5
+ # *object_type* --- \Object Type (ex. Account)<br>
6
+ #
7
+ # *values* --- field values to be assigned<br>
8
+ #
9
+ # *target_org* --- an alias of paticular org, or username can be used<br>
10
+ #
11
+ # ======
12
+ # # create a TheCustomObject record with name and age
13
+ # sf.data.create_record :TheCustomObject__c, values: {Name: "John Smith", Age: 33}
14
+ #
15
+ # For more command details, see {the command reference}[https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_data_commands_unified.htm#cli_reference_data_create_record_unified]
16
+ #
17
+ def create_record(object_type, values: {}, target_org: nil)
18
+ field_values = field_value_pairs(values)
19
+ flags = {
20
+ :"sobject" => object_type,
21
+ :"values" => (field_values.nil? ? nil : %|"#{field_values}"|),
22
+ :"target-org" => target_org,
23
+ }
24
+ action = __method__.to_s.tr('_', ' ')
25
+ json = exec(action, flags: flags, redirection: :null_stderr)
26
+
27
+ json['result']['id']
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,47 @@
1
+ require_relative './bulk_result_v2'
2
+
3
+ module SfCli::Sf::Data
4
+ module DeleteBulk
5
+ # delete records using Bulk API 2.0
6
+ #
7
+ # *file* --- a CSV file, which is written record IDs to delete<br>
8
+ #
9
+ # *sobject* --- \Object Type (ex. Account)<br>
10
+ #
11
+ # *timeout* --- max minutes to wait for the job complete the task.<br>
12
+ #
13
+ # *target_org* --- an alias of paticular org, or username can be used<br>
14
+ #
15
+ # ======
16
+ # # start a delete job
17
+ # jobinfo = sf.data.delete_bulk sobject: :TestCustomObject__c, file: 'delete.csv' # this returns immediately
18
+ # jobinfo.id # => "750J4000003g1OaIAI" it's job ID
19
+ #
20
+ # # you can check if the delete job completed
21
+ # sf.data.delete_resume job_id: jobinfo.id
22
+ #
23
+ # # Or, you can wait for the job completion with one try.
24
+ # result = sf.data.delete_bulk sobject: :TestCustomObject__c, file: 'delete.csv', timeout: 5 # wait within 5 minutes
25
+ #
26
+ # For more command details, see {the command reference}[https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_data_commands_unified.htm#cli_reference_data_delete_bulk_unified]
27
+ #
28
+ def delete_bulk(file:, sobject:, timeout: nil, target_org: nil)
29
+ flags = {
30
+ :"file" => file,
31
+ :"sobject" => sobject,
32
+ :"wait" => timeout,
33
+ :"target-org" => target_org,
34
+ }
35
+ action = __method__.to_s.tr('_', ' ')
36
+ json = exec(action, flags: flags, redirection: :null_stderr)
37
+
38
+ job_info = ::SfCli::Sf::Data::JobInfo.new(**json['result']['jobInfo'])
39
+ return job_info unless json['result']['records']
40
+
41
+ ::SfCli::Sf::Data::BulkResultV2.new(
42
+ job_info: job_info,
43
+ records: ::SfCli::Sf::Data::BulkRecordsV2.new(**json['result']['records'])
44
+ )
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,33 @@
1
+ module SfCli::Sf::Data
2
+ module DeleteRecord
3
+ # delete a object record.
4
+ #
5
+ # *object_type* --- \Object Type (ex. Account)<br>
6
+ #
7
+ # *record_id* --- id of the object<br>
8
+ #
9
+ # *where* --- hash object that is used to identify a record<br>
10
+ #
11
+ # *target_org* --- an alias of paticular org, or username can be used<br>
12
+ #
13
+ # ======
14
+ # sf.data.delete_record :Hoge__c, record_id: 'xxxxxxx'
15
+ # sf.data.delete_record :Hoge__c, where: {Name: 'Jonny B.Good', Country: 'USA'}
16
+ #
17
+ # For more command details, see {the command reference}[https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_data_commands_unified.htm#cli_reference_data_delete_record_unified]
18
+ #
19
+ def delete_record(object_type, record_id: nil, where: nil, target_org: nil)
20
+ where_conditions = field_value_pairs(where)
21
+ flags = {
22
+ :"sobject" => object_type,
23
+ :"record-id" => record_id,
24
+ :"where" => (where_conditions.nil? ? nil : %|"#{where_conditions}"|),
25
+ :"target-org" => target_org,
26
+ }
27
+ action = __method__.to_s.tr('_', ' ')
28
+ json = exec(action, flags: flags, redirection: :null_stderr)
29
+
30
+ json['result']['id']
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,47 @@
1
+ require_relative './bulk_result_v2'
2
+
3
+ module SfCli::Sf::Data
4
+ module DeleteResume
5
+ # resume a bulk delete job you previously started with Bulk API 2.0 and return a bulk result object.
6
+ #
7
+ # *job_id* --- job ID you want to resume<br>
8
+ #
9
+ # *timeout* --- max minutes to wait for the job complete the task.<br>
10
+ #
11
+ # *target_org* --- an alias of paticular org, or username can be used<br>
12
+ #
13
+ # ======
14
+ # # start a delete job
15
+ # jobinfo = sf.data.delete_bulk sobject: :TestCustomObject__c, file: 'delete.csv' # this returns immediately
16
+ # jobinfo.id # => "750J4000003g1OaIAI" it's job ID
17
+ #
18
+ # # the job has already started asynchronously.
19
+ # # So you should check its progress.
20
+ # # if you want to wait for the job complete the task, try 'timeout' option.
21
+ # result = sf.data.delete_resume job_id: jobinfo.id
22
+ #
23
+ # puts 'yey!' if result.job_info.completed? # the job has completed
24
+ #
25
+ # To know more about a job result, take a look at SfCli::Sf::Data module
26
+ #
27
+ # For more command details, see {the command reference}[https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_data_commands_unified.htm#cli_reference_data_delete_resume_unified]
28
+ #
29
+ def delete_resume(job_id:, timeout: nil, target_org: nil)
30
+ flags = {
31
+ :"job-id" => job_id,
32
+ :"wait" => timeout,
33
+ :"target-org" => target_org,
34
+ }
35
+ action = __method__.to_s.tr('_', ' ')
36
+ json = exec(action, flags: flags, redirection: :null_stderr)
37
+
38
+ job_info = ::SfCli::Sf::Data::JobInfo.new(**json['result']['jobInfo'])
39
+ return job_info unless json['result']['records']
40
+
41
+ ::SfCli::Sf::Data::BulkResultV2.new(
42
+ job_info: job_info,
43
+ records: ::SfCli::Sf::Data::BulkRecordsV2.new(**json['result']['records'])
44
+ )
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,42 @@
1
+ module SfCli::Sf::Data
2
+ module GetRecord
3
+
4
+ # get a object record. (eqivalent to *sf* *data* *get* *record*)
5
+ #
6
+ # *object_type* --- \Object Type (ex. Account)<br>
7
+ #
8
+ # *record_id* --- id of the object<br>
9
+ #
10
+ # *where* --- hash object that is used to identify a record<br>
11
+ #
12
+ # *target_org* --- an alias of paticular org, not default one<br>
13
+ #
14
+ # *model_class* --- the object model class<br>
15
+ #
16
+ # ======
17
+ # sf.data.get_record :Account, record_id: 'xxxxxxx'
18
+ # sf.data.get_record :Account, where: {Name: 'Jonny B.Good', Country: 'USA'}
19
+ #
20
+ # CustomObject = Struct.new(:Id, :Name)
21
+ # sf.data.get_record :TheCustomObject__c, record_id: 'xxxxx', model_class: CustomObject # returns a CustomObject instance
22
+ #
23
+ # For more command details, see {the command reference}[https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_data_commands_unified.htm#cli_reference_data_get_record_unified]
24
+ #
25
+ def get_record(object_type, record_id: nil, where: nil, target_org: nil, model_class: nil)
26
+ where_conditions = field_value_pairs(where)
27
+ flags = {
28
+ :"sobject" => object_type,
29
+ :"record-id" => record_id,
30
+ :"where" => (where_conditions.nil? ? nil : %|"#{where_conditions}"|),
31
+ :"target-org" => target_org,
32
+ }
33
+ action = __method__.to_s.tr('_', ' ')
34
+ json = exec(action, flags: flags, redirection: :null_stderr)
35
+
36
+ result = json['result']
37
+ result.delete 'attributes'
38
+
39
+ model_class ? model_class.new(**result) : result
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,47 @@
1
+ module SfCli
2
+ module Sf
3
+ module Data
4
+ module HelperMethods
5
+ def prepare_record(hash) # :doc:
6
+ hash.delete 'attributes'
7
+
8
+ hash.keys.each do |k|
9
+ if parent?(hash[k])
10
+ hash[k] = prepare_record(hash[k])
11
+ elsif children?(hash[k])
12
+ hash[k] = hash[k]['records'].map{|h| prepare_record(h)}
13
+ end
14
+ end
15
+
16
+ hash
17
+ end
18
+
19
+ def prepare_record_in_bulk_mode(hash) # :doc:
20
+ hash.keys.each do |k|
21
+ match_result = /(.*)\.(.*)/.match(k)
22
+ if match_result
23
+ hash[match_result[1]] = {match_result[2] => hash[k]}
24
+ hash.delete k
25
+ end
26
+ end
27
+
28
+ hash
29
+ end
30
+
31
+ def children?(h)
32
+ return false unless h.instance_of?(Hash)
33
+
34
+ h.has_key? 'records'
35
+ end
36
+
37
+ def parent?(h)
38
+ return false unless h.instance_of?(Hash)
39
+
40
+ h.has_key?('records') == false
41
+ end
42
+
43
+ private :prepare_record, :children?, :parent?
44
+ end
45
+ end
46
+ end
47
+ end