sf_cli 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|