sf_cli 0.0.3 → 0.0.4
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/CHANGELOG.md +33 -0
- data/README.rdoc +49 -3
- data/lib/sf_cli/sf/core/base.rb +80 -0
- data/lib/sf_cli/sf/data/core.rb +179 -0
- data/lib/sf_cli/sf/data/helper_methods.rb +35 -0
- data/lib/sf_cli/sf/main.rb +31 -0
- data/lib/sf_cli/sf/model/class_definition.rb +112 -0
- data/lib/sf_cli/sf/model/generator.rb +27 -0
- data/lib/sf_cli/sf/model/schema.rb +33 -0
- data/lib/sf_cli/sf/model.rb +21 -0
- data/lib/sf_cli/sf/org/core.rb +61 -0
- data/lib/sf_cli/sf/project/core.rb +76 -0
- data/lib/sf_cli/sf/sobject/core.rb +48 -0
- data/lib/sf_cli.rb +16 -1
- metadata +17 -10
- data/lib/sf_cli/sf/base.rb +0 -34
- data/lib/sf_cli/sf/data.rb +0 -148
- data/lib/sf_cli/sf/org.rb +0 -49
- data/lib/sf_cli/sf/project.rb +0 -68
- data/lib/sf_cli/sf/sobject.rb +0 -41
- data/lib/sf_cli/sf.rb +0 -87
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9416d015ec2952621fe3525a9ed7177a68b98a86d3bced475eacf19d3ad88ce0
|
4
|
+
data.tar.gz: 545bb5c54d345c194c5b62e8599492a45b13ba156b6ce195d3fb1fe38bb0d656
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf7e32d0d73b0af136d8153b16b05cf837977f37bd2b95c0ab0cecd8fe23bef9cfcb64bda1a1b16dc1ae5ce92fbf239670c4282fd65df28ff0f4bd835f3810cc
|
7
|
+
data.tar.gz: 835a95c35ef507c44d5108b613f7300bd8723428fd897ffc64ce8b0d14d0837929dc416c8259e12b713814903f1e5d59e1832e5d57bb9785f3c9bc397d111f8a
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
## 0.0.4 - 2024-09-02
|
2
|
+
- breaking change:
|
3
|
+
- 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.
|
4
|
+
- sf data query:
|
5
|
+
- support child-parent relationship
|
6
|
+
- support parent-children relationship
|
7
|
+
- add `--result-format` option
|
8
|
+
- auto generation of Object Model (experimental)
|
9
|
+
- generates SF Object Classes automatically
|
10
|
+
- relationship is supported
|
11
|
+
|
12
|
+
## 0.0.3 - 2024-08-25
|
13
|
+
add command operations:
|
14
|
+
|
15
|
+
- sf data get record
|
16
|
+
- sf data create record
|
17
|
+
- sf data update record
|
18
|
+
- sf data delete record
|
19
|
+
|
20
|
+
## 0.0.2 - 2024-08-18
|
21
|
+
this version up was made by mistake.
|
22
|
+
nothing was changed.
|
23
|
+
|
24
|
+
## 0.0.1 - 2024-08-18
|
25
|
+
support some command operations:
|
26
|
+
|
27
|
+
- sf org login web
|
28
|
+
- sf display
|
29
|
+
- sf data query
|
30
|
+
- sf sobject describe
|
31
|
+
- sf sobject list
|
32
|
+
- sf project generate
|
33
|
+
- sf project generate manifest
|
data/README.rdoc
CHANGED
@@ -2,7 +2,7 @@
|
|
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
|
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
|
@@ -21,6 +21,39 @@ 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
|
+
#
|
29
|
+
sf.org.login_web
|
30
|
+
sf.org.login_web target_org: :dev # if the org you login isn't the default one, you should give it alias name for later use.
|
31
|
+
|
32
|
+
#
|
33
|
+
# get records
|
34
|
+
#
|
35
|
+
sf.data.query 'SELECT Id, Name FROM Account LIMIT 1' # => [{Id: "abc", Name: "account name"}]
|
36
|
+
|
37
|
+
Account = Struct.new(:Id, :Name) # you can manually prepare the object model
|
38
|
+
sf.data.query('SELECT Id, Name From Account Limit 3', model_class: Account) # returns an array of Account
|
39
|
+
|
40
|
+
# child-parent relationship is supported
|
41
|
+
sf.data.query 'SELECT Id, Name, Account.Name From Contact Limit 1' # [{Id: "abc", Name: "contact name", Account: {Name: "account name"}}]
|
42
|
+
|
43
|
+
# parent-children relationship is supported
|
44
|
+
sf.data.query 'SELECT Id, Name, (SELECT Name From Contacts) FROM Account Limit 1' # [{Id: "abc", Name: "account name", Contacts: [{Name: "contact name"}]}]
|
45
|
+
|
46
|
+
#
|
47
|
+
# get sobject schema
|
48
|
+
#
|
49
|
+
sf.sobject.describe :Case # get Case Object schema information
|
50
|
+
|
51
|
+
#
|
52
|
+
# generate a Salesforce DX project with manifest generation option
|
53
|
+
#
|
54
|
+
sf.project.generate 'MyProject', manifest: true
|
55
|
+
|
56
|
+
=== Before 0.0.3
|
24
57
|
require 'sf_cli/sf'
|
25
58
|
|
26
59
|
sf = SfCli::Sf.new
|
@@ -38,13 +71,26 @@ then,
|
|
38
71
|
# generate a Salesforce DX project
|
39
72
|
sf.project.generate 'MyProject'
|
40
73
|
|
74
|
+
== \Object Model support (experimental, since 0.0.4)
|
75
|
+
require 'sf_cli'
|
76
|
+
require 'sf_cli/sf/model'
|
77
|
+
|
78
|
+
# generates Model Class for Contact and Account, accessing the org aliased as 'dev'
|
79
|
+
SfCli::Sf::Model.generate %w[Contact Account], target_org: :dev
|
80
|
+
|
81
|
+
c = Contact.new(:Name => "John Smith")
|
82
|
+
c.Name # => "John Smith"
|
41
83
|
|
42
|
-
|
84
|
+
rows = sf.data.query 'SELECT Id, Name, Account.Name From Contact Limit 1', model_class: Contact
|
85
|
+
rows.size # => 1
|
86
|
+
rows.first.Name # => Name of the Contact
|
87
|
+
rows.first.Account.Name # => Name of the Account
|
43
88
|
|
44
89
|
== Documents
|
90
|
+
The following steps generate *doc* directory, which all documents are generated in.
|
45
91
|
$ git clone https://github.com/tmkw/sf_cli.git
|
46
92
|
$ cd sf_cli
|
47
93
|
$ bundle install
|
48
94
|
$ bundle exec rake rdoc
|
49
95
|
|
50
|
-
|
96
|
+
*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,179 @@
|
|
1
|
+
require_relative '../core/base'
|
2
|
+
require_relative './helper_methods'
|
3
|
+
|
4
|
+
module SfCli
|
5
|
+
module Sf
|
6
|
+
module Data
|
7
|
+
#
|
8
|
+
# ==== description
|
9
|
+
# The class representing *sf* *data*
|
10
|
+
#
|
11
|
+
# https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_data_commands_unified.htm
|
12
|
+
#
|
13
|
+
class Core
|
14
|
+
include ::SfCli::Sf::Core::Base
|
15
|
+
include ::SfCli::Sf::Data::HelperMethods
|
16
|
+
|
17
|
+
# get object records using SQOL. (eqivalent to *sf* *data* *query*)
|
18
|
+
#
|
19
|
+
# *soql* --- SOQL<br>
|
20
|
+
# *target_org* --- an alias of paticular org, not default one<br>
|
21
|
+
# *model_class* --- the object model class<br>
|
22
|
+
#
|
23
|
+
# == examples
|
24
|
+
# sf.data.query 'SELECT Id, Name FROM Account LIMIT 1' # => [{Id: "abc", Name: "account name"}]
|
25
|
+
#
|
26
|
+
# Account = Struct.new(:Id, :Name)
|
27
|
+
# sf.data.query('SELECT Id, Name From Account Limit 3', model_class: Account) # returns an array of Account struct object
|
28
|
+
#
|
29
|
+
# # child-parent relationship is supported
|
30
|
+
# sf.data.query 'SELECT Id, Name, Account.Name From Contact Limit 1' # [{Id: "abc", Name: "contact name", Account: {Name: "account name"}}]
|
31
|
+
#
|
32
|
+
# # parent-children relationship is supported
|
33
|
+
# sf.data.query 'SELECT Id, Name, (SELECT Name From Contacts) FROM Account Limit 1' # [{Id: "abc", Name: "account name", Contacts: [{Name: "contact name"}]}]
|
34
|
+
#
|
35
|
+
# Account = Struct.new(:Id, :Name) # you can manually prepare the object model
|
36
|
+
# sf.data.query('SELECT Id, Name From Account Limit 3', model_class: Account) # returns an array of Account
|
37
|
+
#
|
38
|
+
# 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]
|
39
|
+
#
|
40
|
+
# 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.
|
41
|
+
#
|
42
|
+
def query(soql, target_org: nil, format: nil, model_class: nil)
|
43
|
+
flags = {
|
44
|
+
:"query" => %("#{soql}"),
|
45
|
+
:"target-org" => target_org,
|
46
|
+
:"result-format" => format,
|
47
|
+
}
|
48
|
+
|
49
|
+
raw_output = format ? true : false
|
50
|
+
format = format || :json
|
51
|
+
|
52
|
+
result = exec(__method__, flags: flags, redirection: :null_stderr, raw_output: raw_output, format: format)
|
53
|
+
return result if raw_output
|
54
|
+
|
55
|
+
result['result']['records'].each_with_object([]) do |h, a|
|
56
|
+
record = prepare_record(h)
|
57
|
+
a << (model_class ? model_class.new(**record) : record)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# get a object record. (eqivalent to *sf* *data* *get* *record*)
|
62
|
+
#
|
63
|
+
# *object_type* --- \Object Type (ex. Account)<br>
|
64
|
+
# *record_id* --- id of the object<br>
|
65
|
+
# *where* --- hash object that is used to identify a record<br>
|
66
|
+
# *target_org* --- an alias of paticular org, not default one<br>
|
67
|
+
# *model_class* --- the object model class<br>
|
68
|
+
#
|
69
|
+
# ==== examples
|
70
|
+
# sf.data.get_record :Account, record_id: 'xxxxxxx'
|
71
|
+
# sf.data.get_record :Account, where: {Name: 'Jonny B.Good', Country: 'USA'}
|
72
|
+
#
|
73
|
+
# CustomObject = Struct.new(:Id, :Name)
|
74
|
+
# sf.data.get_record :TheCustomObject__c, record_id: 'xxxxx', model_class: CustomObject # returns a CustomObject struct object
|
75
|
+
#
|
76
|
+
# 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]
|
77
|
+
#
|
78
|
+
def get_record(object_type, record_id: nil, where: nil, target_org: nil, model_class: nil)
|
79
|
+
where_conditions = field_value_pairs(where)
|
80
|
+
flags = {
|
81
|
+
:"sobject" => object_type,
|
82
|
+
:"record-id" => record_id,
|
83
|
+
:"where" => (where_conditions.nil? ? nil : %|"#{where_conditions}"|),
|
84
|
+
:"target-org" => target_org,
|
85
|
+
}
|
86
|
+
action = __method__.to_s.tr('_', ' ')
|
87
|
+
json = exec(action, flags: flags, redirection: :null_stderr)
|
88
|
+
|
89
|
+
result = json['result']
|
90
|
+
result.delete 'attributes'
|
91
|
+
|
92
|
+
model_class ? model_class.new(**result) : result
|
93
|
+
end
|
94
|
+
|
95
|
+
# update a object record. (eqivalent to *sf* *data* *update* *record*)
|
96
|
+
#
|
97
|
+
# *object_type* --- \Object Type (ex. Account)<br>
|
98
|
+
# *record_id* --- id of the object<br>
|
99
|
+
# *where* --- field values that is used to identify a record<br>
|
100
|
+
# *values* --- field values for update<br>
|
101
|
+
# *target_org* --- an alias of paticular org, not default one<br>
|
102
|
+
#
|
103
|
+
# ==== examples
|
104
|
+
# sf.data.update_record :Account, record_id: 'xxxxxxx', values: {Name: 'New Account Name'}
|
105
|
+
# sf.data.update_record :Hoge__c, where: {Name: 'Jonny B.Good', Country: 'USA'}, values: {Phone: 'xxxxx', bar: 2000}
|
106
|
+
#
|
107
|
+
# 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]
|
108
|
+
#
|
109
|
+
def update_record(object_type, record_id: nil, where: nil, values: nil, target_org: nil)
|
110
|
+
where_conditions = field_value_pairs(where)
|
111
|
+
field_values = field_value_pairs(values)
|
112
|
+
flags = {
|
113
|
+
:"sobject" => object_type,
|
114
|
+
:"record-id" => record_id,
|
115
|
+
:"where" => (where_conditions.nil? ? nil : %|"#{where_conditions}"|),
|
116
|
+
:"values" => (field_values.nil? ? nil : %|"#{field_values}"|),
|
117
|
+
:"target-org" => target_org,
|
118
|
+
}
|
119
|
+
action = __method__.to_s.tr('_', ' ')
|
120
|
+
json = exec(action, flags: flags, redirection: :null_stderr)
|
121
|
+
|
122
|
+
json['result']['id']
|
123
|
+
end
|
124
|
+
|
125
|
+
# create a object record. (eqivalent to *sf* *data* *create* *record*)
|
126
|
+
#
|
127
|
+
# *object_type* --- \Object Type (ex. Account)<br>
|
128
|
+
# *values* --- field values to be assigned<br>
|
129
|
+
# *target_org* --- an alias of paticular org, not default one<br>
|
130
|
+
#
|
131
|
+
# ==== examples
|
132
|
+
#
|
133
|
+
# sf.data.create_record :TheCustomObject__c, values: {Name: "John Smith", Age: 33} # creating a TheCustomObject record with name and age
|
134
|
+
#
|
135
|
+
# 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]
|
136
|
+
#
|
137
|
+
def create_record(object_type, values: {}, target_org: nil)
|
138
|
+
field_values = field_value_pairs(values)
|
139
|
+
flags = {
|
140
|
+
:"sobject" => object_type,
|
141
|
+
:"values" => (field_values.nil? ? nil : %|"#{field_values}"|),
|
142
|
+
:"target-org" => target_org,
|
143
|
+
}
|
144
|
+
action = __method__.to_s.tr('_', ' ')
|
145
|
+
json = exec(action, flags: flags, redirection: :null_stderr)
|
146
|
+
|
147
|
+
json['result']['id']
|
148
|
+
end
|
149
|
+
|
150
|
+
# delete a object record. (eqivalent to *sf* *data* *delete* *record*)
|
151
|
+
#
|
152
|
+
# *object_type* --- \Object Type (ex. Account)<br>
|
153
|
+
# *record_id* --- id of the object<br>
|
154
|
+
# *where* --- hash object that is used to identify a record<br>
|
155
|
+
# *target_org* --- an alias of paticular org, not default one<br>
|
156
|
+
#
|
157
|
+
# ==== examples
|
158
|
+
# sf.data.delete_record :Hoge__c, record_id: 'xxxxxxx'
|
159
|
+
# sf.data.delete_record :Hoge__c, where: {Name: 'Jonny B.Good', Country: 'USA'}
|
160
|
+
#
|
161
|
+
# 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]
|
162
|
+
#
|
163
|
+
def delete_record(object_type, record_id: nil, where: nil, target_org: nil)
|
164
|
+
where_conditions = field_value_pairs(where)
|
165
|
+
flags = {
|
166
|
+
:"sobject" => object_type,
|
167
|
+
:"record-id" => record_id,
|
168
|
+
:"where" => (where_conditions.nil? ? nil : %|"#{where_conditions}"|),
|
169
|
+
:"target-org" => target_org,
|
170
|
+
}
|
171
|
+
action = __method__.to_s.tr('_', ' ')
|
172
|
+
json = exec(action, flags: flags, redirection: :null_stderr)
|
173
|
+
|
174
|
+
json['result']['id']
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
@@ -0,0 +1,35 @@
|
|
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 children?(h)
|
20
|
+
return false unless h.instance_of?(Hash)
|
21
|
+
|
22
|
+
h.has_key? 'records'
|
23
|
+
end
|
24
|
+
|
25
|
+
def parent?(h)
|
26
|
+
return false unless h.instance_of?(Hash)
|
27
|
+
|
28
|
+
h.has_key?('records') == false
|
29
|
+
end
|
30
|
+
|
31
|
+
private :prepare_record, :children?, :parent?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module SfCli
|
5
|
+
module Sf
|
6
|
+
# ==== description
|
7
|
+
# The entry class of sf command. It is returned by sf method.
|
8
|
+
# With including Singleton module, the instance of this class is guaranteed as singleton.
|
9
|
+
#
|
10
|
+
# ==== examples
|
11
|
+
# sf # returns a instance of SfCli::Sf
|
12
|
+
# sf.org.display # you can follow the similar syntax to the original command by using method chain.
|
13
|
+
#
|
14
|
+
class Main
|
15
|
+
include Singleton
|
16
|
+
|
17
|
+
OPERATION_CATEGORIES = %w[Org Sobject Data Project]
|
18
|
+
|
19
|
+
OPERATION_CATEGORIES.each do |category|
|
20
|
+
require_relative %(#{category.downcase}/core)
|
21
|
+
attr_reader category.downcase.to_sym
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
OPERATION_CATEGORIES.each do |category|
|
26
|
+
instance_variable_set(:"@#{category.downcase}", Object.const_get(%|::SfCli::Sf::#{category}::Core|).new)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require_relative './schema'
|
2
|
+
|
3
|
+
module SfCli
|
4
|
+
module Sf
|
5
|
+
module Model
|
6
|
+
class ClassDefinition
|
7
|
+
attr_reader :schema
|
8
|
+
|
9
|
+
def initialize(schema)
|
10
|
+
@schema = Schema.new(schema)
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
<<~Klass
|
15
|
+
Class.new do
|
16
|
+
#{ class_methods }
|
17
|
+
|
18
|
+
field_names.each do |name|
|
19
|
+
attr_accessor name
|
20
|
+
end
|
21
|
+
|
22
|
+
#{ parent_relation_methods }
|
23
|
+
#{ children_relation_methods }
|
24
|
+
|
25
|
+
#{ define_initialize }
|
26
|
+
|
27
|
+
#{ define_to_h }
|
28
|
+
end
|
29
|
+
Klass
|
30
|
+
end
|
31
|
+
|
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
|
+
def class_methods
|
65
|
+
<<~EOS
|
66
|
+
class << self
|
67
|
+
def field_names
|
68
|
+
@field_names ||= #{ schema.field_names }
|
69
|
+
end
|
70
|
+
|
71
|
+
def parent_relations
|
72
|
+
@parent_relations ||= #{ schema.parent_relations }
|
73
|
+
end
|
74
|
+
|
75
|
+
def children_relations
|
76
|
+
@children_relations ||= #{ schema.children_relations }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
EOS
|
80
|
+
end
|
81
|
+
|
82
|
+
def parent_relation_methods
|
83
|
+
schema.parent_relations.each_with_object('') do |r, s|
|
84
|
+
s << <<~EOS
|
85
|
+
def #{r[:name]}
|
86
|
+
@#{r[:name]}
|
87
|
+
end
|
88
|
+
|
89
|
+
def #{r[:name]}=(attributes)
|
90
|
+
@#{r[:name]} = #{r[:class_name]}.new(attributes)
|
91
|
+
end
|
92
|
+
EOS
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def children_relation_methods
|
97
|
+
schema.children_relations.each_with_object('') do |r, s|
|
98
|
+
s << <<~EOS
|
99
|
+
def #{r[:name]}
|
100
|
+
@#{r[:name]}
|
101
|
+
end
|
102
|
+
|
103
|
+
def #{r[:name]}=(records)
|
104
|
+
@#{r[:name]} = records.map{|attributes| #{r[:class_name]}.new(attributes)}
|
105
|
+
end
|
106
|
+
EOS
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative '../sobject/core'
|
2
|
+
require_relative './class_definition'
|
3
|
+
|
4
|
+
module SfCli
|
5
|
+
module Sf
|
6
|
+
module Model
|
7
|
+
class Generator
|
8
|
+
attr_reader :sf_sobject, :target_org
|
9
|
+
|
10
|
+
def initialize(target_org: nil)
|
11
|
+
@sf_sobject = ::SfCli::Sf::Sobject::Core.new
|
12
|
+
@target_org = target_org
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate(object_name)
|
16
|
+
class_definition = ClassDefinition.new(describe object_name)
|
17
|
+
|
18
|
+
instance_eval "::#{object_name} = #{class_definition}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def describe(object_name)
|
22
|
+
sf_sobject.describe object_name, target_org: target_org
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module SfCli
|
2
|
+
module Sf
|
3
|
+
module Model
|
4
|
+
class Schema
|
5
|
+
attr_reader :schema
|
6
|
+
|
7
|
+
def initialize(schema)
|
8
|
+
@schema = schema
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
schema['name']
|
13
|
+
end
|
14
|
+
|
15
|
+
def field_names
|
16
|
+
schema['fields'].map{|f| f['name'].to_sym}
|
17
|
+
end
|
18
|
+
|
19
|
+
def children_relations
|
20
|
+
schema['childRelationships']
|
21
|
+
.select{|r| r['relationshipName'].nil? == false}
|
22
|
+
.map{|r| {name: r['relationshipName'].to_sym, class_name: r['childSObject'].to_sym}}
|
23
|
+
end
|
24
|
+
|
25
|
+
def parent_relations
|
26
|
+
schema['fields']
|
27
|
+
.select{|f| f['relationshipName'].nil? == false && f['referenceTo']&.size > 0}
|
28
|
+
.map{|f| {name: f['relationshipName'].to_sym, class_name: f['referenceTo'].first.to_sym}}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'model/generator'
|
2
|
+
|
3
|
+
module SfCli
|
4
|
+
module Sf
|
5
|
+
#
|
6
|
+
# ==== description
|
7
|
+
# The module for \Object \Model definition and generation
|
8
|
+
#
|
9
|
+
# see the section {"Object Model support"}[link://files/README_rdoc.html#label-Object+Model+support+-28experimental-2C+since+0.0.4-29] in README.
|
10
|
+
#
|
11
|
+
module Model
|
12
|
+
def self.generate(object_names, target_org: nil)
|
13
|
+
generator = Generator.new(target_org: target_org)
|
14
|
+
|
15
|
+
object_names.each do |object_name|
|
16
|
+
generator.generate(object_name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative '../core/base'
|
2
|
+
|
3
|
+
module SfCli
|
4
|
+
module Sf
|
5
|
+
module Org
|
6
|
+
#
|
7
|
+
# ==== description
|
8
|
+
# The class representing *sf* *org*.
|
9
|
+
#
|
10
|
+
# https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_org_commands_unified.htm
|
11
|
+
#
|
12
|
+
class Core
|
13
|
+
include ::SfCli::Sf::Core::Base
|
14
|
+
|
15
|
+
ConnectionInfo = Struct.new(:id, :access_token, :alias, :instance_url, :user_name, :api_version, :status)
|
16
|
+
|
17
|
+
# login to the org by the browser. (equivalent to *sf* *org* *login* *web*)
|
18
|
+
#
|
19
|
+
# *target_org* --- an alias of paticular org, not default one<br>
|
20
|
+
# *instance_url* --- custom login url.
|
21
|
+
#
|
22
|
+
# == examples:
|
23
|
+
# sf.org.login_web
|
24
|
+
# sf.org.login_web target_org: :dev # if the org you login isn't the default one, you should give it alias name for later use.
|
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_org_commands_unified.htm#cli_reference_org_login_web_unified]
|
27
|
+
#
|
28
|
+
def login_web(target_org: nil, instance_url: nil)
|
29
|
+
flags = {
|
30
|
+
:"alias" => target_org,
|
31
|
+
:"instance-url" => instance_url,
|
32
|
+
}
|
33
|
+
action = __method__.to_s.tr('_', ' ')
|
34
|
+
exec(action, flags: flags)
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# returns the org's connection information. (equivalent to *sf* *org* *display*)
|
39
|
+
#
|
40
|
+
# *target_org* --- an alias of paticular org, not default one<br>
|
41
|
+
#
|
42
|
+
# 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_org_commands_unified.htm#cli_reference_org_display_unified]
|
43
|
+
#
|
44
|
+
def display(target_org: nil)
|
45
|
+
flags = {:"target-org" => target_org}
|
46
|
+
json = exec(__method__, flags: flags, redirection: :null_stderr)
|
47
|
+
|
48
|
+
ConnectionInfo.new(
|
49
|
+
id: json['result']['id'],
|
50
|
+
access_token: json['result']['accessToken'],
|
51
|
+
alias: json['result']['alias'],
|
52
|
+
instance_url: json['result']['instanceUrl'],
|
53
|
+
user_name: json['result']['username'],
|
54
|
+
api_version: json['result']['apiVersion'],
|
55
|
+
status: json['result']['connectedStatus']
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require_relative '../core/base'
|
2
|
+
|
3
|
+
module SfCli
|
4
|
+
module Sf
|
5
|
+
module Project
|
6
|
+
# ==== description
|
7
|
+
# The class representing *sf* *project*
|
8
|
+
#
|
9
|
+
# command reference: https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_project_commands_unified.htm
|
10
|
+
#
|
11
|
+
class Core
|
12
|
+
include ::SfCli::Sf::Core::Base
|
13
|
+
|
14
|
+
GenerateResult = Struct.new(:output_dir, :files, :raw_output, :warnings)
|
15
|
+
|
16
|
+
#
|
17
|
+
# generate a Salesforce project. (equivalent to *sf* *project* *generate*)
|
18
|
+
#
|
19
|
+
# *name* --- project name<br>
|
20
|
+
# *template* --- project template name<br>
|
21
|
+
# *output_dir* --- output directory<br>
|
22
|
+
# *manifest* --- switch to create manifest file in the project directory (manifest/package.xml). default: false
|
23
|
+
#
|
24
|
+
# For more command details, see the {reference document}[https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_project_commands_unified.htm#cli_reference_project_generate_unified]
|
25
|
+
#
|
26
|
+
def generate(name, manifest: false, template: nil, output_dir: nil)
|
27
|
+
flags = {
|
28
|
+
:name => name,
|
29
|
+
:template => template,
|
30
|
+
:"output-dir" => output_dir,
|
31
|
+
}
|
32
|
+
switches = {
|
33
|
+
manifest: manifest,
|
34
|
+
}
|
35
|
+
json = exec(__method__, flags: flags, switches: switches, redirection: :null_stderr)
|
36
|
+
|
37
|
+
GenerateResult.new(
|
38
|
+
output_dir: json['result']['outputDir'],
|
39
|
+
files: json['result']['created'],
|
40
|
+
raw_output: json['result']['rawOutput'],
|
41
|
+
warnings: json['warnings']
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
# generate the manifest file of a Salesforce project. (equivalent to *sf* *project* *generate* *manifest*)
|
46
|
+
#
|
47
|
+
# *metadata* --- an array that consists of metadata type like CustomObject, Layout and so on. (default: [])<br>
|
48
|
+
# *api_verson* --- api version (default: nil)<br>
|
49
|
+
# *output_dir* --- manifest's output directory in the project directory. You can use relative path from the project root (default: nil)<br>
|
50
|
+
# *from_org* --- username or alias of the org that contains the metadata components from which to build a manifest (default: nil)<br>
|
51
|
+
# *source_dir* --- paths to the local source files to include in the manifest (default: nil)
|
52
|
+
#
|
53
|
+
# == examples
|
54
|
+
# sf.project.generate_manifest metadata: %w[CustomObject Layout] # creates a package.xml, which is initialized with CustomObject and Layout
|
55
|
+
# sf.project.generate_manifest from_org: <org_name> # creates a package.xml, which is initialized with all metadata types in the org
|
56
|
+
#
|
57
|
+
# For more command details, see the {reference document}[https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_project_commands_unified.htm#cli_reference_project_generate_manifest_unified]
|
58
|
+
#
|
59
|
+
def generate_manifest(name: nil, output_dir: nil, api_version: nil, metadata: [], from_org: nil, source_dir: nil)
|
60
|
+
flags = {
|
61
|
+
:name => name,
|
62
|
+
:"metadata" => (metadata.empty? ? nil : metadata.join(' ')),
|
63
|
+
:"from-org" => from_org,
|
64
|
+
:"source-dir" => source_dir,
|
65
|
+
:"output-dir" => output_dir,
|
66
|
+
:"api-version" => api_version,
|
67
|
+
}
|
68
|
+
action = __method__.to_s.tr('_', ' ')
|
69
|
+
json = exec(action, flags: flags, redirection: :null_stderr)
|
70
|
+
|
71
|
+
json['result']['path']
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative '../core/base'
|
2
|
+
|
3
|
+
module SfCli
|
4
|
+
module Sf
|
5
|
+
module Sobject
|
6
|
+
# ==== description
|
7
|
+
# The class representing *sf* *sobject*
|
8
|
+
#
|
9
|
+
# command reference: https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_sobject_commands_unified.htm
|
10
|
+
#
|
11
|
+
class Core
|
12
|
+
include ::SfCli::Sf::Core::Base
|
13
|
+
|
14
|
+
# returns a hash object containing the Salesforce object schema. (equivalent to *sf* *sobject* *describe*)
|
15
|
+
#
|
16
|
+
# *objectType* --- object type (ex: Account)<br>
|
17
|
+
# *target_org* --- an alias of paticular org, not default one<br>
|
18
|
+
#
|
19
|
+
# 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_sobject_commands_unified.htm#cli_reference_sobject_describe_unified]
|
20
|
+
#
|
21
|
+
def describe(object_type, target_org: nil)
|
22
|
+
flags = {
|
23
|
+
:"sobject" => object_type,
|
24
|
+
:"target-org" => target_org,
|
25
|
+
}
|
26
|
+
json = exec(__method__, flags: flags, redirection: :null_stderr)
|
27
|
+
json['result']
|
28
|
+
end
|
29
|
+
|
30
|
+
# returns a list of Salesforce object API name. (equivalent to *sf* *sobject* *list*)
|
31
|
+
#
|
32
|
+
# *object_type* --- all or custom<br>
|
33
|
+
# *target_org* --- an alias of paticular org, not default one<br>
|
34
|
+
#
|
35
|
+
# 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_sobject_commands_unified.htm#cli_reference_sobject_list_unified]
|
36
|
+
#
|
37
|
+
def list(object_type, target_org: nil)
|
38
|
+
flags = {
|
39
|
+
:"sobject" => (object_type.to_sym == :custom ? :custom : :all),
|
40
|
+
:"target-org" => target_org,
|
41
|
+
}
|
42
|
+
json = exec(__method__, flags: flags, redirection: :null_stderr)
|
43
|
+
json['result']
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/sf_cli.rb
CHANGED
@@ -1 +1,16 @@
|
|
1
|
-
require 'sf_cli/sf'
|
1
|
+
require 'sf_cli/sf/main'
|
2
|
+
#
|
3
|
+
# the global method that represents *sf* command.
|
4
|
+
# This is desgined as the syntax suger, which can use with similar usability to the original.
|
5
|
+
#
|
6
|
+
# For command details, see the {reference document}[https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_unified.htm]
|
7
|
+
#
|
8
|
+
# == examples
|
9
|
+
# # you can follow the similar syntax to the original command by using method chain.
|
10
|
+
#
|
11
|
+
# sf.org.display # same as original command 'sf org display'
|
12
|
+
# sf.data.query "SELECT Name FROM Account" # same as original command 'sf data query "SELECT Name FROM Account"`
|
13
|
+
#
|
14
|
+
def sf
|
15
|
+
SfCli::Sf::Main.instance
|
16
|
+
end
|
metadata
CHANGED
@@ -1,31 +1,38 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sf_cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Takanobu Maekawa
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: This is a class library for introducing Salesforce CLI.
|
14
|
-
sf command is the target of development.
|
13
|
+
description: This is a class library for introducing Salesforce CLI to Ruby scripting.
|
14
|
+
Currenty only sf command is the target of development.
|
15
15
|
email:
|
16
16
|
executables: []
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files:
|
19
19
|
- README.rdoc
|
20
|
+
- CHANGELOG.md
|
20
21
|
files:
|
22
|
+
- CHANGELOG.md
|
21
23
|
- README.rdoc
|
22
24
|
- lib/sf_cli.rb
|
23
|
-
- lib/sf_cli/sf.rb
|
24
|
-
- lib/sf_cli/sf/
|
25
|
-
- lib/sf_cli/sf/data.rb
|
26
|
-
- lib/sf_cli/sf/
|
27
|
-
- lib/sf_cli/sf/
|
28
|
-
- lib/sf_cli/sf/
|
25
|
+
- lib/sf_cli/sf/core/base.rb
|
26
|
+
- lib/sf_cli/sf/data/core.rb
|
27
|
+
- lib/sf_cli/sf/data/helper_methods.rb
|
28
|
+
- lib/sf_cli/sf/main.rb
|
29
|
+
- lib/sf_cli/sf/model.rb
|
30
|
+
- lib/sf_cli/sf/model/class_definition.rb
|
31
|
+
- lib/sf_cli/sf/model/generator.rb
|
32
|
+
- lib/sf_cli/sf/model/schema.rb
|
33
|
+
- lib/sf_cli/sf/org/core.rb
|
34
|
+
- lib/sf_cli/sf/project/core.rb
|
35
|
+
- lib/sf_cli/sf/sobject/core.rb
|
29
36
|
homepage: https://github.com/tmkw/sf_cli
|
30
37
|
licenses:
|
31
38
|
- MIT
|
data/lib/sf_cli/sf/base.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
module SfCli
|
2
|
-
class Sf
|
3
|
-
class Base
|
4
|
-
def initialize(_sf)
|
5
|
-
@sf = _sf
|
6
|
-
end
|
7
|
-
|
8
|
-
private
|
9
|
-
|
10
|
-
def exec(action, flags: {}, switches: {}, redirection: nil)
|
11
|
-
sf.exec(category, action, flags: flags, switches: switches, redirection: redirection)
|
12
|
-
end
|
13
|
-
|
14
|
-
def category
|
15
|
-
self.class.name.split('::').last.downcase
|
16
|
-
end
|
17
|
-
|
18
|
-
def field_value_pairs(hash)
|
19
|
-
return nil if hash.nil?
|
20
|
-
return nil if hash.empty?
|
21
|
-
|
22
|
-
hash.each_with_object([]) do|(k,v), arr|
|
23
|
-
value = v.instance_of?(String) ? %|'#{v}'| : v
|
24
|
-
arr << %(#{k}=#{value})
|
25
|
-
end
|
26
|
-
.join(' ')
|
27
|
-
end
|
28
|
-
|
29
|
-
def sf
|
30
|
-
@sf
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
data/lib/sf_cli/sf/data.rb
DELETED
@@ -1,148 +0,0 @@
|
|
1
|
-
require_relative './base'
|
2
|
-
|
3
|
-
module SfCli
|
4
|
-
class Sf
|
5
|
-
#
|
6
|
-
# ==== description
|
7
|
-
# The class representing *sf* *data*
|
8
|
-
#
|
9
|
-
# https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_data_commands_unified.htm
|
10
|
-
#
|
11
|
-
class Data < Base
|
12
|
-
|
13
|
-
# get object records using SQOL. (eqivalent to *sf* *data* *query*)
|
14
|
-
#
|
15
|
-
# *soql* --- SOQL<br>
|
16
|
-
# *target_org* --- an alias of paticular org, not default one<br>
|
17
|
-
# *model_class* --- the data model class representing the record object.<br>
|
18
|
-
#
|
19
|
-
# ==== examples
|
20
|
-
# sf.data.query('SELECT Id, Name From Account Limit 3') # returns an array of Hash object
|
21
|
-
#
|
22
|
-
# Account = Struct.new(:Id, :Name)
|
23
|
-
# sf.data.query('SELECT Id, Name From Account Limit 3', model_class: Account) # returns an array of Account struct object
|
24
|
-
#
|
25
|
-
def query(soql, target_org: nil, model_class: nil)
|
26
|
-
flags = {
|
27
|
-
:"query" => %("#{soql}"),
|
28
|
-
:"target-org" => target_org,
|
29
|
-
}
|
30
|
-
json = exec(__method__, flags: flags, redirection: :null_stderr)
|
31
|
-
|
32
|
-
json['result']['records'].each_with_object([]) do |h, a|
|
33
|
-
h.delete "attributes"
|
34
|
-
a << (model_class ? model_class.new(**h) : h)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# get a object record. (eqivalent to *sf* *data* *get* *record*)
|
39
|
-
#
|
40
|
-
# *object_type* --- Object Type (ex. Account)<br>
|
41
|
-
# *record_id* --- id of the object<br>
|
42
|
-
# *where* --- hash object that is used to identify a record<br>
|
43
|
-
# *target_org* --- an alias of paticular org, not default one<br>
|
44
|
-
# *model_class* --- the data model class representing the record object.<br>
|
45
|
-
#
|
46
|
-
# ==== examples
|
47
|
-
# sf.data.get_record :Account, record_id: 'xxxxxxx'
|
48
|
-
# sf.data.get_record :Account, where: {Name: 'Jonny B.Good', Country: 'USA'}
|
49
|
-
#
|
50
|
-
# CustomObject = Struct.new(:Id, :Name)
|
51
|
-
# sf.data.get_record :TheCustomObject__c, record_id: 'xxxxx', model_class: CustomObject # returns a CustomObject struct object
|
52
|
-
#
|
53
|
-
def get_record(object_type, record_id: nil, where: nil, target_org: nil, model_class: nil)
|
54
|
-
where_conditions = field_value_pairs(where)
|
55
|
-
flags = {
|
56
|
-
:"sobject" => object_type,
|
57
|
-
:"record-id" => record_id,
|
58
|
-
:"where" => (where_conditions.nil? ? nil : %|"#{where_conditions}"|),
|
59
|
-
:"target-org" => target_org,
|
60
|
-
}
|
61
|
-
action = __method__.to_s.tr('_', ' ')
|
62
|
-
json = exec(action, flags: flags, redirection: :null_stderr)
|
63
|
-
|
64
|
-
result = json['result']
|
65
|
-
result.delete 'attributes'
|
66
|
-
|
67
|
-
model_class ? model_class.new(**result) : result
|
68
|
-
end
|
69
|
-
|
70
|
-
# update a object record. (eqivalent to *sf* *data* *update* *record*)
|
71
|
-
#
|
72
|
-
# *object_type* --- Object Type (ex. Account)<br>
|
73
|
-
# *record_id* --- id of the object<br>
|
74
|
-
# *where* --- field values that is used to identify a record<br>
|
75
|
-
# *values* --- field values for update<br>
|
76
|
-
# *target_org* --- an alias of paticular org, not default one<br>
|
77
|
-
#
|
78
|
-
# ==== examples
|
79
|
-
# sf.data.update_record :Account, record_id: 'xxxxxxx', values: {Name: 'New Account Name'}
|
80
|
-
# sf.data.update_record :Hoge__c, where: {Name: 'Jonny B.Good', Country: 'USA'}, values: {Phone: 'xxxxx', bar: 2000}
|
81
|
-
#
|
82
|
-
def update_record(object_type, record_id: nil, where: nil, values: nil, target_org: nil)
|
83
|
-
where_conditions = field_value_pairs(where)
|
84
|
-
field_values = field_value_pairs(values)
|
85
|
-
flags = {
|
86
|
-
:"sobject" => object_type,
|
87
|
-
:"record-id" => record_id,
|
88
|
-
:"where" => (where_conditions.nil? ? nil : %|"#{where_conditions}"|),
|
89
|
-
:"values" => (field_values.nil? ? nil : %|"#{field_values}"|),
|
90
|
-
:"target-org" => target_org,
|
91
|
-
}
|
92
|
-
action = __method__.to_s.tr('_', ' ')
|
93
|
-
json = exec(action, flags: flags, redirection: :null_stderr)
|
94
|
-
|
95
|
-
json['result']['id']
|
96
|
-
end
|
97
|
-
|
98
|
-
# create a object record. (eqivalent to *sf* *data* *create* *record*)
|
99
|
-
#
|
100
|
-
# *object_type* --- Object Type (ex. Account)<br>
|
101
|
-
# *values* --- field values to be assigned<br>
|
102
|
-
# *target_org* --- an alias of paticular org, not default one<br>
|
103
|
-
#
|
104
|
-
# ==== examples
|
105
|
-
#
|
106
|
-
# sf.data.create_record :TheCustomObject__c, values: {Name: "John Smith", Age: 33} # creating a TheCustomObject record with name and age
|
107
|
-
#
|
108
|
-
def create_record(object_type, values: {}, target_org: nil)
|
109
|
-
field_values = field_value_pairs(values)
|
110
|
-
flags = {
|
111
|
-
:"sobject" => object_type,
|
112
|
-
:"values" => (field_values.nil? ? nil : %|"#{field_values}"|),
|
113
|
-
:"target-org" => target_org,
|
114
|
-
}
|
115
|
-
action = __method__.to_s.tr('_', ' ')
|
116
|
-
json = exec(action, flags: flags, redirection: :null_stderr)
|
117
|
-
|
118
|
-
json['result']['id']
|
119
|
-
end
|
120
|
-
|
121
|
-
# delete a object record. (eqivalent to *sf* *data* *delete* *record*)
|
122
|
-
#
|
123
|
-
# *object_type* --- Object Type (ex. Account)<br>
|
124
|
-
# *record_id* --- id of the object<br>
|
125
|
-
# *where* --- hash object that is used to identify a record<br>
|
126
|
-
# *target_org* --- an alias of paticular org, not default one<br>
|
127
|
-
#
|
128
|
-
# ==== examples
|
129
|
-
# sf.data.delete_record :Hoge__c, record_id: 'xxxxxxx'
|
130
|
-
# sf.data.delete_record :Hoge__c, where: {Name: 'Jonny B.Good', Country: 'USA'}
|
131
|
-
#
|
132
|
-
#
|
133
|
-
def delete_record(object_type, record_id: nil, where: nil, target_org: nil)
|
134
|
-
where_conditions = field_value_pairs(where)
|
135
|
-
flags = {
|
136
|
-
:"sobject" => object_type,
|
137
|
-
:"record-id" => record_id,
|
138
|
-
:"where" => (where_conditions.nil? ? nil : %|"#{where_conditions}"|),
|
139
|
-
:"target-org" => target_org,
|
140
|
-
}
|
141
|
-
action = __method__.to_s.tr('_', ' ')
|
142
|
-
json = exec(action, flags: flags, redirection: :null_stderr)
|
143
|
-
|
144
|
-
json['result']['id']
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
data/lib/sf_cli/sf/org.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
require_relative './base'
|
2
|
-
|
3
|
-
module SfCli
|
4
|
-
class Sf
|
5
|
-
#
|
6
|
-
# ==== description
|
7
|
-
# The class representing *sf* *org*.
|
8
|
-
#
|
9
|
-
# https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_org_commands_unified.htm
|
10
|
-
#
|
11
|
-
class Org < Base
|
12
|
-
ConnectionInfo = Struct.new(:id, :access_token, :alias, :instance_url, :user_name, :api_version, :status)
|
13
|
-
|
14
|
-
# login to the org by the browser. (equivalent to *sf* *org* *login* *web*)
|
15
|
-
#
|
16
|
-
# *target_org* --- an alias of paticular org, not default one<br>
|
17
|
-
# *instance_url* --- custom login url.
|
18
|
-
#
|
19
|
-
def login_web(target_org: nil, instance_url: nil)
|
20
|
-
flags = {
|
21
|
-
:"alias" => target_org,
|
22
|
-
:"instance-url" => instance_url,
|
23
|
-
}
|
24
|
-
action = __method__.to_s.tr('_', ' ')
|
25
|
-
exec(action, flags: flags)
|
26
|
-
end
|
27
|
-
|
28
|
-
#
|
29
|
-
# returns the org's connection information. (equivalent to *sf* *org* *display*)
|
30
|
-
#
|
31
|
-
# *target_org* --- an alias of paticular org, not default one<br>
|
32
|
-
#
|
33
|
-
def display(target_org: nil)
|
34
|
-
flags = {:"target-org" => target_org}
|
35
|
-
json = exec(__method__, flags: flags, redirection: :null_stderr)
|
36
|
-
|
37
|
-
ConnectionInfo.new(
|
38
|
-
id: json['result']['id'],
|
39
|
-
access_token: json['result']['accessToken'],
|
40
|
-
alias: json['result']['alias'],
|
41
|
-
instance_url: json['result']['instanceUrl'],
|
42
|
-
user_name: json['result']['username'],
|
43
|
-
api_version: json['result']['apiVersion'],
|
44
|
-
status: json['result']['connectedStatus']
|
45
|
-
)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
data/lib/sf_cli/sf/project.rb
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
require_relative './base'
|
2
|
-
|
3
|
-
module SfCli
|
4
|
-
class Sf
|
5
|
-
# ==== description
|
6
|
-
# The class representing *sf* *project*
|
7
|
-
#
|
8
|
-
# command reference: https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_project_commands_unified.htm
|
9
|
-
#
|
10
|
-
class Project < Base
|
11
|
-
GenerateResult = Struct.new(:output_dir, :files, :raw_output, :warnings)
|
12
|
-
|
13
|
-
#
|
14
|
-
# generate a Salesforce project. (equivalent to *sf* *project* *generate*)
|
15
|
-
#
|
16
|
-
# *name* --- project name<br>
|
17
|
-
# *template* --- project template name<br>
|
18
|
-
# *output_dir* --- output directory<br>
|
19
|
-
# *manifest* --- switch to create manifest file in the project directory (manifest/package.xml). default: false
|
20
|
-
#
|
21
|
-
def generate(name, manifest: false, template: nil, output_dir: nil)
|
22
|
-
flags = {
|
23
|
-
:name => name,
|
24
|
-
:template => template,
|
25
|
-
:"output-dir" => output_dir,
|
26
|
-
}
|
27
|
-
switches = {
|
28
|
-
manifest: manifest,
|
29
|
-
}
|
30
|
-
json = exec(__method__, flags: flags, switches: switches, redirection: :null_stderr)
|
31
|
-
|
32
|
-
GenerateResult.new(
|
33
|
-
output_dir: json['result']['outputDir'],
|
34
|
-
files: json['result']['created'],
|
35
|
-
raw_output: json['result']['rawOutput'],
|
36
|
-
warnings: json['warnings']
|
37
|
-
)
|
38
|
-
end
|
39
|
-
|
40
|
-
# generate the manifest file of a Salesforce project. (equivalent to *sf* *project* *generate* *manifest*)
|
41
|
-
#
|
42
|
-
# *metadata* --- an array that consists of metadata type like CustomObject, Layout and so on. (default: [])<br>
|
43
|
-
# *api_verson* --- api version (default: nil)<br>
|
44
|
-
# *output_dir* --- manifest's output directory in the project directory. You can use relative path from the project root (default: nil)<br>
|
45
|
-
# *from_org* --- username or alias of the org that contains the metadata components from which to build a manifest (default: nil)<br>
|
46
|
-
# *source_dir* --- paths to the local source files to include in the manifest (default: nil)
|
47
|
-
#
|
48
|
-
# ==== examples
|
49
|
-
# sf.project.generate_manifest metadata: %w[CustomObject Layout] # creates a package.xml, which is initialized with CustomObject and Layout
|
50
|
-
# sf.project.generate_manifest from_org: <org_name> # creates a package.xml, which is initialized with all metadata types in the org
|
51
|
-
#
|
52
|
-
def generate_manifest(name: nil, output_dir: nil, api_version: nil, metadata: [], from_org: nil, source_dir: nil)
|
53
|
-
flags = {
|
54
|
-
:name => name,
|
55
|
-
:"metadata" => (metadata.empty? ? nil : metadata.join(' ')),
|
56
|
-
:"from-org" => from_org,
|
57
|
-
:"source-dir" => source_dir,
|
58
|
-
:"output-dir" => output_dir,
|
59
|
-
:"api-version" => api_version,
|
60
|
-
}
|
61
|
-
action = __method__.to_s.tr('_', ' ')
|
62
|
-
json = exec(action, flags: flags, redirection: :null_stderr)
|
63
|
-
|
64
|
-
json['result']['path']
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
data/lib/sf_cli/sf/sobject.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
require_relative './base'
|
2
|
-
|
3
|
-
module SfCli
|
4
|
-
class Sf
|
5
|
-
# ==== description
|
6
|
-
# The class representing *sf* *sobject*
|
7
|
-
#
|
8
|
-
# command reference: https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_sobject_commands_unified.htm
|
9
|
-
#
|
10
|
-
class Sobject < Base
|
11
|
-
|
12
|
-
# returns a hash object containing the Salesforce object schema. (equivalent to *sf* *sobject* *describe*)
|
13
|
-
#
|
14
|
-
# *objectType* --- object type (ex: Account)<br>
|
15
|
-
# *target_org* --- an alias of paticular org, not default one<br>
|
16
|
-
#
|
17
|
-
def describe(object_type, target_org: nil)
|
18
|
-
flags = {
|
19
|
-
:"sobject" => object_type,
|
20
|
-
:"target-org" => target_org,
|
21
|
-
}
|
22
|
-
json = exec(__method__, flags: flags, redirection: :null_stderr)
|
23
|
-
json['result']
|
24
|
-
end
|
25
|
-
|
26
|
-
# returns a list of Salesforce object API name. (equivalent to *sf* *sobject* *list*)
|
27
|
-
#
|
28
|
-
# *object_type* --- all or custom<br>
|
29
|
-
# *target_org* --- an alias of paticular org, not default one<br>
|
30
|
-
#
|
31
|
-
def list(object_type, target_org: nil)
|
32
|
-
flags = {
|
33
|
-
:"sobject" => (object_type.to_sym == :custom ? :custom : :all),
|
34
|
-
:"target-org" => target_org,
|
35
|
-
}
|
36
|
-
json = exec(__method__, flags: flags, redirection: :null_stderr)
|
37
|
-
json['result']
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
data/lib/sf_cli/sf.rb
DELETED
@@ -1,87 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
module SfCli
|
4
|
-
# ==== description
|
5
|
-
# The main class of *sf* command.
|
6
|
-
#
|
7
|
-
# https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_unified.htm
|
8
|
-
#
|
9
|
-
# ==== examples
|
10
|
-
# sf = SfCli::Sf.new # use default org
|
11
|
-
#
|
12
|
-
# # get the org connection infomation, as same as 'sf org display'
|
13
|
-
# sf.org.display
|
14
|
-
#
|
15
|
-
# # get Account records (equivalent to 'sf data query')
|
16
|
-
# sf.data.query 'SELECT Id, Name FROM Account LIMIT 3' # => returns an array containing 3 records
|
17
|
-
#
|
18
|
-
class Sf
|
19
|
-
OPERATION_CATEGORIES = %w[Org Sobject Data Project]
|
20
|
-
|
21
|
-
# load each operation class and define as a attribute
|
22
|
-
OPERATION_CATEGORIES.each do |category|
|
23
|
-
require_relative %(sf/#{category.downcase})
|
24
|
-
attr_reader category.downcase.to_sym
|
25
|
-
end
|
26
|
-
|
27
|
-
attr_reader :varbose
|
28
|
-
|
29
|
-
def initialize
|
30
|
-
OPERATION_CATEGORIES.each do |category|
|
31
|
-
instance_variable_set(:"@#{category.downcase}", Object.const_get(%|::SfCli::Sf::#{category}|).new(self))
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def exec(category, action, flags: {}, switches: {}, redirection: nil)
|
36
|
-
cmd = %|sf #{category} #{action}#{as_flag_options(flags)}#{as_switch_options(switches)}#{redirect redirection}|
|
37
|
-
|
38
|
-
puts cmd if varbose
|
39
|
-
|
40
|
-
json = JSON.parse `#{cmd}`
|
41
|
-
|
42
|
-
puts json if varbose
|
43
|
-
|
44
|
-
raise StandardError.new(json['message']) if json['status'] != 0
|
45
|
-
|
46
|
-
json
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def as_flag_options(hash)
|
52
|
-
flag_options = hash.map{|k,v| flag k, v}.reject(&:nil?).join(' ')
|
53
|
-
flag_options = ' ' + flag_options unless flag_options.empty?
|
54
|
-
|
55
|
-
flag_options
|
56
|
-
end
|
57
|
-
|
58
|
-
def as_switch_options(hash)
|
59
|
-
' ' + {json: true}.merge(hash).each_with_object([]){|(k,v), arr| arr << %(--#{k}) if v}.join(' ')
|
60
|
-
end
|
61
|
-
|
62
|
-
def flag(name, arg)
|
63
|
-
arg ? %(--#{name} #{arg}) : nil
|
64
|
-
end
|
65
|
-
|
66
|
-
def os
|
67
|
-
@os ||= ENV['OS']
|
68
|
-
end
|
69
|
-
|
70
|
-
def redirect(option)
|
71
|
-
case option
|
72
|
-
when :null_stderr
|
73
|
-
null_stderr_redirection
|
74
|
-
else
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def null_stderr_redirection
|
79
|
-
@null_stderr_redirection ||=
|
80
|
-
if os.eql?('Windows_NT')
|
81
|
-
' 2>nul'
|
82
|
-
else
|
83
|
-
' 2> /dev/null'
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|