sf_cli 0.0.4 → 0.0.6

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -2
  3. data/README.rdoc +85 -40
  4. data/lib/sf_cli/sf/core/base.rb +2 -0
  5. data/lib/sf_cli/sf/data/bulk_result_v2.rb +77 -0
  6. data/lib/sf_cli/sf/data/core.rb +22 -162
  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 +12 -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/model/base_methods.rb +62 -0
  21. data/lib/sf_cli/sf/model/class_definition.rb +34 -43
  22. data/lib/sf_cli/sf/model/dml_methods.rb +36 -0
  23. data/lib/sf_cli/sf/model/generator.rb +8 -7
  24. data/lib/sf_cli/sf/model/query_condition.rb +136 -0
  25. data/lib/sf_cli/sf/model/query_methods.rb +58 -0
  26. data/lib/sf_cli/sf/model/sf_command_connection.rb +60 -0
  27. data/lib/sf_cli/sf/model.rb +10 -2
  28. data/lib/sf_cli/sf/org/core.rb +6 -44
  29. data/lib/sf_cli/sf/org/display.rb +41 -0
  30. data/lib/sf_cli/sf/org/list.rb +67 -0
  31. data/lib/sf_cli/sf/org/login.rb +64 -0
  32. data/lib/sf_cli/sf/project/core.rb +10 -3
  33. data/lib/sf_cli/sf/sobject/core.rb +15 -5
  34. data/lib/sf_cli/sf/sobject/schema.rb +47 -0
  35. data/lib/sf_cli.rb +8 -5
  36. metadata +29 -8
  37. data/lib/sf_cli/sf/model/schema.rb +0 -33
@@ -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
@@ -16,6 +16,18 @@ module SfCli
16
16
  hash
17
17
  end
18
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
+
19
31
  def children?(h)
20
32
  return false unless h.instance_of?(Hash)
21
33
 
@@ -0,0 +1,120 @@
1
+ require_relative './helper_methods'
2
+ require_relative './query_helper'
3
+
4
+ module SfCli::Sf::Data
5
+ module Query
6
+ # get object records using SOQL.
7
+ #
8
+ # *soql* --- SOQL<br>
9
+ #
10
+ # *target_org* --- an alias of paticular org, or username can be used<br>
11
+ #
12
+ # *format* --- get the command's raw output. human, csv, json can be available<br>
13
+ #
14
+ # *model_class* --- the object model class<br>
15
+ #
16
+ # *bulk* --- use Bulk API<br>
17
+ #
18
+ # *timeout* --- max minutes to wait for the job complete in Bulk API mode<br>
19
+ #
20
+ # ======
21
+ # sf.data.query 'SELECT Id, Name FROM Account LIMIT 1' # => [{Id: "abc", Name: "account name"}]
22
+ #
23
+ # Account = Struct.new(:Id, :Name)
24
+ # sf.data.query('SELECT Id, Name From Account Limit 3', model_class: Account) # returns an array of Account struct object
25
+ #
26
+ # # child-parent relationship is supported
27
+ # sf.data.query 'SELECT Id, Name, Account.Name From Contact Limit 1' # [{Id: "abc", Name: "contact name", Account: {Name: "account name"}}]
28
+ #
29
+ # # parent-children relationship is supported
30
+ # sf.data.query 'SELECT Id, Name, (SELECT Name From Contacts) FROM Account Limit 1' # [{Id: "abc", Name: "account name", Contacts: [{Name: "contact name"}]}]
31
+ #
32
+ # When using Bulk API, you get the records when the query job completes within time limit.
33
+ # The method returns a tapple(an array), which changes its contents according to the job result.
34
+ #
35
+ # ======
36
+ # done, result = sf.data.query 'SELECT Id, Name FROM Account', bulk: true # max wait 1 min to get result (default)
37
+ # done, result = sf.data.query 'SELECT Id, Name FROM Account', bulk: true, timeout: 5 # max wait 5 min to get result
38
+ # done, result = sf.data.query 'SELECT Id, Name FROM Account', bulk: true, timeout: 0 # returns immediately
39
+ #
40
+ # rows = result if done # if job is completed, the result is an array of record
41
+ # job_id = result unless done # if job hasn't completed or it has aborted, the result is the job ID
42
+ #
43
+ # 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_query_unified]
44
+ #
45
+ # About querying with auto generated object model, see the section {"Object Model support"}[link://files/README_rdoc.html#label-Object+Model+support+-28experimental-2C+since+0.0.4-29] in README.
46
+ #
47
+ def query(soql, target_org: nil, format: nil, bulk: false, timeout: nil, model_class: nil)
48
+ flags = {
49
+ :"query" => %("#{soql}"),
50
+ :"target-org" => target_org,
51
+ :"result-format" => format,
52
+ :"wait" => (bulk ? timeout : nil),
53
+ }
54
+ switches = {
55
+ bulk: bulk,
56
+ }
57
+ raw_output = format ? true : false
58
+ format = format&.to_sym || :json
59
+
60
+ result = exec(__method__, flags: flags, switches: switches, redirection: :null_stderr, raw_output: raw_output, format: format)
61
+
62
+ return_result(result, raw_output, bulk, model_class)
63
+ end
64
+
65
+ # resume a bulk query job, which you previously started, and get records
66
+ #
67
+ # *job_id* --- job ID you want to resume<br>
68
+ #
69
+ # *target_org* --- an alias of paticular org, or username can be used<br>
70
+ #
71
+ # *format* --- get the command's raw output. human, csv, json can be available<br>
72
+ #
73
+ # *model_class* --- the object model class<br>
74
+ #
75
+ # ======
76
+ # # start a query job
77
+ # result1 = sf.data.query 'SELECT Id, Name FROM Account', bulk: true, timeout: 0 # returns immediately
78
+ #
79
+ # result1 # => [false, "<job id>"]
80
+ #
81
+ # # the job has already started asynchronously.
82
+ # # So you should check and get the result.
83
+ # done, result2 = sf.data.query_resume job_id: result1.last
84
+ #
85
+ # puts 'get the records!' if done # the job has completed
86
+ #
87
+ # result2 # => if done is true, this is an array of record. Otherwise it should be the Job ID.
88
+ #
89
+ # 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_query_resume_unified]
90
+ def query_resume(job_id:, target_org: nil, format: nil, model_class: nil)
91
+ flags = {
92
+ :"bulk-query-id" => job_id,
93
+ :"target-org" => target_org,
94
+ :"result-format" => format,
95
+ }
96
+ raw_output = format ? true : false
97
+ format = format || :json
98
+
99
+ action = __method__.to_s.tr('_', ' ')
100
+ result = exec(action, flags: flags, redirection: :null_stderr, raw_output: raw_output, format: format)
101
+
102
+ return_result(result, raw_output, true, model_class)
103
+ end
104
+
105
+ def return_result(result, raw_output, bulk, model_class)
106
+ result_adjuster =
107
+ if raw_output
108
+ RawOutputResultAdjuster.new(result)
109
+ elsif bulk
110
+ BulkResultAdjuster.new(result, model_class)
111
+ else
112
+ RegularResultAdjuster.new(result, model_class)
113
+ end
114
+
115
+ result_adjuster.get_return_value
116
+ end
117
+
118
+ private :return_result
119
+ end
120
+ end
@@ -0,0 +1,57 @@
1
+ require_relative './helper_methods'
2
+
3
+ module SfCli::Sf::Data
4
+ module Query
5
+ class RegularResultAdjuster # :nodoc: all
6
+ include ::SfCli::Sf::Data::HelperMethods
7
+
8
+ attr_reader :result, :model_class
9
+
10
+ def initialize(result, model_class)
11
+ @result = result
12
+ @model_class = model_class
13
+ end
14
+
15
+ def get_return_value
16
+ result['result']['records'].each_with_object([]) do |h, a|
17
+ record = prepare_record(h)
18
+ a << (model_class ? model_class.new(**record) : record)
19
+ end
20
+ end
21
+ end
22
+
23
+ class BulkResultAdjuster # :nodoc: all
24
+ include ::SfCli::Sf::Data::HelperMethods
25
+
26
+ attr_reader :result, :model_class
27
+
28
+ def initialize(result, model_class)
29
+ @result = result
30
+ @model_class = model_class
31
+ end
32
+
33
+ def get_return_value
34
+ done = result['result']['done']
35
+ id = result['result']['id']
36
+ rows = result['result']['records'].each_with_object([]) do |h, a|
37
+ record = prepare_record_in_bulk_mode(h)
38
+ a << (model_class ? model_class.new(**record) : record)
39
+ end
40
+
41
+ done ? [done, rows] : [done, id]
42
+ end
43
+ end
44
+
45
+ class RawOutputResultAdjuster # :nodoc: all
46
+ attr_reader :result
47
+
48
+ def initialize(result)
49
+ @result = result
50
+ end
51
+
52
+ def get_return_value
53
+ result
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,87 @@
1
+ module SfCli::Sf::Data
2
+ module Resume
3
+ JobInfo = Struct.new(
4
+ :id,
5
+ :operation,
6
+ :object,
7
+ :createdById,
8
+ :createdDate,
9
+ :systemModstamp,
10
+ :state,
11
+ :concurrencyMode,
12
+ :contentType,
13
+ :numberBatchesQueued,
14
+ :numberBatchesInProgress,
15
+ :numberBatchesCompleted,
16
+ :numberBatchesFailed,
17
+ :numberBatchesTotal,
18
+ :numberRecordsProcessed,
19
+ :numberRetries,
20
+ :apiVersion,
21
+ :numberRecordsFailed,
22
+ :totalProcessingTime,
23
+ :apiActiveProcessingTime,
24
+ :apexProcessingTime
25
+ ) do
26
+ def opened?
27
+ state == 'Open'
28
+ end
29
+
30
+ def upload_completed?
31
+ state == 'UploadComplete'
32
+ end
33
+
34
+ def in_progress?
35
+ state == 'InProgress'
36
+ end
37
+
38
+ def completed?
39
+ state == 'JobComplete'
40
+ end
41
+
42
+ def failed?
43
+ state == 'Failed'
44
+ end
45
+
46
+ def aborted?
47
+ state == 'Aborted'
48
+ end
49
+ end
50
+
51
+ # View the status of a bulk job.
52
+ #
53
+ # *job_id* --- job ID you want to resume<br>
54
+ #
55
+ # *target_org* --- an alias of paticular org, or username can be used<br>
56
+ #
57
+ # ======
58
+ # # start a delete job
59
+ # jobinfo = sf.data.delete_bulk sobject: :TestCustomObject__c, file: 'delete.csv' # this returns immediately
60
+ # jobinfo.id # => "750J4000003g1OaIAI" it's job ID
61
+ #
62
+ # jobinfo2 = sf.data.resume job_id: jobinfo.id
63
+ #
64
+ # puts 'yey!' if job_info2.completed? # the job has completed
65
+ #
66
+ # The job info object has methods to check the job status:
67
+ # - opened?
68
+ # - upload_completed?
69
+ # - in_progress?
70
+ # - completed?
71
+ #
72
+ # To know job status more, take a look at {the bulk API developer guide}[https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/bulk_api_2_job_states.htm]
73
+ #
74
+ # 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_resume_unified]
75
+ #
76
+ def resume(job_id:, target_org: nil)
77
+ flags = {
78
+ :"job-id" => job_id,
79
+ :"target-org" => target_org,
80
+ }
81
+ json = exec(__method__, flags: flags, redirection: :null_stderr)
82
+
83
+ json['result'].delete '$'
84
+ JobInfo.new(**json['result'])
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,50 @@
1
+ module SfCli::Sf::Data
2
+ module Search
3
+ # search objects using SOSL.
4
+ #
5
+ # *sosl* --- SOSL<br>
6
+ #
7
+ # *target_org* --- an alias of paticular org, or username can be used<br>
8
+ #
9
+ # *format* --- get the command's raw output. human, csv, json can be available. *NOTE*: if you choose csv, csv files are downloaded in current directory<br>
10
+ #
11
+ # ======
12
+ # # example (in irb):
13
+ #
14
+ # > sf.data.search "FIND {TIM OR YOUNG OR OIL} IN Name Fields"
15
+ # =>
16
+ # {"Lead"=>["00Q5j00000WgEuDEAV"],
17
+ # "Account"=>["0015j00001U2XvNAAV", "0015j00001U2XvMAAV", "0015j00001U2XvJAAV"],
18
+ # "Contact"=>
19
+ # ["0035j00001HB84BAAT",
20
+ # "0035j00001HB84DAAT"],
21
+ # "Opportunity"=>
22
+ # ["0065j00001XHJLjAAP",
23
+ # "0065j00001XHJLTAA5",
24
+ # "0065j00001XHJLJAA5"],
25
+ # "User"=>["0055j00000CcL2bAAF", "0055j00000CcL1YAAV"]}
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_search_unified]
28
+ #
29
+ def search(sosl, target_org: nil, format: nil)
30
+ flags = {
31
+ :"query" => %|"#{sosl}"|,
32
+ :"target-org" => target_org,
33
+ :"result-format" => format,
34
+ }
35
+ raw_output = format ? true : false
36
+ format = format&.to_sym || :json
37
+
38
+ result = exec(__method__, flags: flags, redirection: :null_stderr, raw_output: raw_output, format: format)
39
+
40
+ return if format == :csv
41
+ return result if format == :human
42
+
43
+ result['result']['searchRecords']
44
+ .group_by{|r| r['attributes']['type']}
45
+ .each_with_object({}) do |(object_type, records), result|
46
+ result[object_type] = records.map{|r| r['Id']}
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,38 @@
1
+ module SfCli::Sf::Data
2
+ module UpdateRecord
3
+
4
+ # update a object record.
5
+ #
6
+ # *object_type* --- \Object Type (ex. Account)<br>
7
+ #
8
+ # *record_id* --- id of the object<br>
9
+ #
10
+ # *where* --- field values that is used to identify a record<br>
11
+ #
12
+ # *values* --- field values for update<br>
13
+ #
14
+ # *target_org* --- an alias of paticular org, or username can be used<br>
15
+ #
16
+ # ==== examples
17
+ # sf.data.update_record :Account, record_id: 'xxxxxxx', values: {Name: 'New Account Name'}
18
+ # sf.data.update_record :Hoge__c, where: {Name: 'Jonny B.Good', Country: 'USA'}, values: {Phone: 'xxxxx', bar: 2000}
19
+ #
20
+ # 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_update_record_unified]
21
+ #
22
+ def update_record(object_type, record_id: nil, where: nil, values: nil, target_org: nil)
23
+ where_conditions = field_value_pairs(where)
24
+ field_values = field_value_pairs(values)
25
+ flags = {
26
+ :"sobject" => object_type,
27
+ :"record-id" => record_id,
28
+ :"where" => (where_conditions.nil? ? nil : %|"#{where_conditions}"|),
29
+ :"values" => (field_values.nil? ? nil : %|"#{field_values}"|),
30
+ :"target-org" => target_org,
31
+ }
32
+ action = __method__.to_s.tr('_', ' ')
33
+ json = exec(action, flags: flags, redirection: :null_stderr)
34
+
35
+ json['result']['id']
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,50 @@
1
+ require_relative './bulk_result_v2'
2
+
3
+ module SfCli::Sf::Data
4
+ module UpsertBulk
5
+ # update records using Bulk API 2.0
6
+ #
7
+ # *file* --- a \CSV file for update records<br>
8
+ #
9
+ # *sobject* --- \Object Type (ex. Account)<br>
10
+ #
11
+ # *external_id* --- Name of the external ID field, or the Id field<br>
12
+ #
13
+ # *timeout* --- max minutes to wait for the job complete the task.<br>
14
+ #
15
+ # *target_org* --- an alias of paticular org, or username can be used<br>
16
+ #
17
+ # ======
18
+ # # start a upsert job
19
+ # jobinfo = sf.data.upsert_bulk sobject: :TestCustomObject__c, file: 'upsert.csv' # this returns immediately
20
+ # jobinfo.id # => "750J4000003g1OaIAI" it's job ID
21
+ #
22
+ # # you can check if the upsert job completed
23
+ # sf.data.upsert_resume job_id: jobinfo.id
24
+ #
25
+ # # Or, you can wait for the job completion with one try.
26
+ # result = sf.data.upsert_bulk sobject: :TestCustomObject__c, file: 'upsert.csv', timeout: 5 # wait within 5 minutes
27
+ #
28
+ # 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_upsert_bulk_unified]
29
+ #
30
+ def upsert_bulk(file:, sobject:, external_id:, timeout: nil, target_org: nil)
31
+ flags = {
32
+ :"file" => file,
33
+ :"sobject" => sobject,
34
+ :"external-id" => external_id,
35
+ :"wait" => timeout,
36
+ :"target-org" => target_org,
37
+ }
38
+ action = __method__.to_s.tr('_', ' ')
39
+ json = exec(action, flags: flags, redirection: :null_stderr)
40
+
41
+ job_info = ::SfCli::Sf::Data::JobInfo.new(**json['result']['jobInfo'])
42
+ return job_info unless json['result']['records']
43
+
44
+ ::SfCli::Sf::Data::BulkResultV2.new(
45
+ job_info: job_info,
46
+ records: ::SfCli::Sf::Data::BulkRecordsV2.new(**json['result']['records'])
47
+ )
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,47 @@
1
+ require_relative './bulk_result_v2'
2
+
3
+ module SfCli::Sf::Data
4
+ module UpsertResume
5
+ # resume a bulk upsert 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 upsert job
15
+ # jobinfo = sf.data.upsert_bulk sobject: :TestCustomObject__c, file: 'upsert.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.upsert_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_upsert_resume_unified]
28
+ #
29
+ def upsert_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,62 @@
1
+ module SfCli
2
+ module Sf
3
+ module Model
4
+ module BaseMethods
5
+ def self.included(c)
6
+ c.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def connection
11
+ @connection
12
+ end
13
+
14
+ def connection=(conn)
15
+ @connection = conn
16
+ end
17
+
18
+ def describe
19
+ connection.describe(name.to_sym)
20
+ end
21
+ end
22
+
23
+ def initialize(attributes = {})
24
+ @original_attributes = {}
25
+ @current_attributes = {}
26
+ @updated_attributes = {}
27
+
28
+ attributes.each do |k, v|
29
+ field_name = k.to_sym
30
+ if self.class.field_names.include?(field_name)
31
+ @original_attributes[field_name] = v
32
+ __send__ (field_name.to_s + '='), v
33
+ elsif self.class.parent_relations.find{|r| r[:name] == field_name}
34
+ __send__ (field_name.to_s + '='), v
35
+ elsif self.class.children_relations.find{|r| r[:name] == field_name}
36
+ __send__ (field_name.to_s + '='), (v.nil? ? [] : v)
37
+ end
38
+ end
39
+ end
40
+
41
+ def to_h(keys: nil)
42
+ self.class.field_names.each_with_object({}) do |name, hash|
43
+ if keys&.instance_of?(Array)
44
+ hash[name] = __send__(name) if keys.include?(name)
45
+ else
46
+ hash[name] = __send__(name)
47
+ end
48
+ end
49
+ end
50
+
51
+ def new_record?
52
+ self.Id.nil?
53
+ end
54
+
55
+ def persisted?
56
+ new_record? == false
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+
@@ -1,4 +1,6 @@
1
- require_relative './schema'
1
+ require_relative './base_methods'
2
+ require_relative './dml_methods'
3
+ require_relative './query_methods'
2
4
 
3
5
  module SfCli
4
6
  module Sf
@@ -7,60 +9,27 @@ module SfCli
7
9
  attr_reader :schema
8
10
 
9
11
  def initialize(schema)
10
- @schema = Schema.new(schema)
12
+ @schema = schema
11
13
  end
12
14
 
13
15
  def to_s
14
16
  <<~Klass
15
17
  Class.new do
16
- #{ class_methods }
18
+ include ::SfCli::Sf::Model::BaseMethods
19
+ include ::SfCli::Sf::Model::DmlMethods
20
+ include ::SfCli::Sf::Model::QueryMethods
17
21
 
18
- field_names.each do |name|
19
- attr_accessor name
20
- end
22
+ attr_reader :original_attributes, :current_attributes, :updated_attributes
23
+
24
+ #{ class_methods }
21
25
 
26
+ #{ field_attribute_methods }
22
27
  #{ parent_relation_methods }
23
28
  #{ children_relation_methods }
24
-
25
- #{ define_initialize }
26
-
27
- #{ define_to_h }
28
29
  end
29
30
  Klass
30
31
  end
31
32
 
32
- def define_initialize
33
- <<~EOS
34
- def initialize(attributes = {})
35
- attributes.each do |k, v|
36
- field_name = k.to_sym
37
- if self.class.field_names.include?(field_name)
38
- #instance_variable_set ('@' + field_name.to_s).to_sym, v
39
- __send__ (field_name.to_s + '='), v
40
- elsif self.class.parent_relations.find{|r| r[:name] == field_name}
41
- __send__ (field_name.to_s + '='), v
42
- elsif self.class.children_relations.find{|r| r[:name] == field_name}
43
- __send__ (field_name.to_s + '='), (v.nil? ? [] : v)
44
- end
45
- end
46
- end
47
- EOS
48
- end
49
-
50
- def define_to_h
51
- <<~EOS
52
- def to_h(keys: nil)
53
- self.class.field_names.each_with_object({}) do |name, hash|
54
- if keys&.instance_of?(Array)
55
- hash[name] = __send__(name) if keys.include?(name)
56
- else
57
- hash[name] = __send__(name)
58
- end
59
- end
60
- end
61
- EOS
62
- end
63
-
64
33
  def class_methods
65
34
  <<~EOS
66
35
  class << self
@@ -79,6 +48,28 @@ module SfCli
79
48
  EOS
80
49
  end
81
50
 
51
+ def field_attribute_methods
52
+ schema.field_names.each_with_object('') do |name, s|
53
+ s << <<~EOS
54
+ def #{name}
55
+ @#{name}
56
+ end
57
+
58
+ def #{name}=(value)
59
+ @#{name} = value
60
+ return if %i[Id LastModifiedDate IsDeleted SystemModstamp CreatedById CreatedDate LastModifiedById].include?(:#{name})
61
+
62
+ current_attributes[:#{name}] = value
63
+ if current_attributes[:#{name}] == original_attributes[:#{name}]
64
+ updated_attributes[:#{name}] = nil
65
+ else
66
+ updated_attributes[:#{name}] = value
67
+ end
68
+ end
69
+ EOS
70
+ end
71
+ end
72
+
82
73
  def parent_relation_methods
83
74
  schema.parent_relations.each_with_object('') do |r, s|
84
75
  s << <<~EOS
@@ -87,7 +78,7 @@ module SfCli
87
78
  end
88
79
 
89
80
  def #{r[:name]}=(attributes)
90
- @#{r[:name]} = #{r[:class_name]}.new(attributes)
81
+ @#{r[:name]} = attributes.nil? ? nil : #{r[:class_name]}.new(attributes)
91
82
  end
92
83
  EOS
93
84
  end