gd_salesforce 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ my-bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in salesforce.gemspec
4
+ gemspec
data/README.markdown ADDED
@@ -0,0 +1,47 @@
1
+ This is a wrapper for couple of things I usually do with SF
2
+ ===========================================================
3
+
4
+ Installation
5
+ ------------
6
+
7
+ Prerequisite is having git, ruby and gems installed (also you should have XCode installed since there probably will be need to compile some C code in the background).
8
+
9
+ gem install bundler
10
+ git clone git://github.com/fluke777/salesforce.git
11
+ cd salesforce
12
+ bundle install
13
+ rake install
14
+
15
+
16
+ Grabbing fields of a module
17
+ ---------------------------
18
+ Since Force.com explorer cannot search in fields and I love my text editor too much. I created a command how to download the list of fields
19
+
20
+ require 'rubygems'
21
+ require 'salesforce'
22
+
23
+ client = Salesforce::Client.new('login', 'pass+token')
24
+ fields = client.fields('Account')
25
+
26
+ # if you are looking for a specific one
27
+ fields.grep /Customer/i
28
+
29
+ # if you did not want a api name you can do whatever you want with describe. For example here I am grabbing label
30
+ response = client.describe('Account')
31
+ response[:describeSObjectResponse][:result][:fields].map {|field| field[:label]}
32
+
33
+ Downloading data
34
+ ----------------
35
+ You can grab easily some data. Paging is implemented so it will download all the data.
36
+
37
+ # grabbing into array (this should probably be the default and it should return the field rather than pasing a reference inside)
38
+ x = []
39
+ client.grab :module => "User", :output => x, :fields => 'Id, Name'
40
+ x.count
41
+
42
+ # storing it into a file as CSV is easy as well
43
+ require 'fastercsv'
44
+
45
+ FasterCSV.open('my-csv.csv', 'w') do |csv|
46
+ client.grab :module => "User", :output => csv, :fields => 'Id, Name'
47
+ end
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,3 @@
1
+ module Salesforce
2
+ VERSION = "0.0.1"
3
+ end
data/lib/salesforce.rb ADDED
@@ -0,0 +1,174 @@
1
+ require 'salesforce/version'
2
+ require 'rforce'
3
+ require 'fastercsv'
4
+ require 'active_support/time'
5
+ require 'pry'
6
+
7
+ module Salesforce
8
+
9
+ class Client
10
+
11
+ attr_accessor :rforce_binding
12
+
13
+ def initialize(login, pass, options = {})
14
+ server = options[:server] || "www.salesforce.com"
15
+ url = options[:url] || "https://#{server}/services/Soap/u/26.0"
16
+ @rforce_binding = RForce::Binding.new url
17
+ @rforce_binding.login login, pass
18
+ end
19
+
20
+ def describe(mod)
21
+ @rforce_binding.describeSObject(:sObject => mod)
22
+ end
23
+
24
+ def modules
25
+ g = @rforce_binding.describeGlobal
26
+ modules = g[:describeGlobalResponse][:result][:sobjects]
27
+ end
28
+
29
+ def fields(mod)
30
+ result = @rforce_binding.describeSObject(:sObject => mod)
31
+ if result.has_key?(:Fault)
32
+ fail result
33
+ end
34
+ fields = result[:describeSObjectResponse][:result][:fields]
35
+ fields.map {|f| f[:name]}
36
+ end
37
+
38
+ def grab(options)
39
+ sf_module = options[:module] || fail("Specify SFDC module")
40
+ fields = options[:fields]
41
+ rforce_binding = @rforce_binding
42
+ output = options[:output]
43
+
44
+ if fields == :all
45
+ fields = fields(sf_module)
46
+ elsif fields.kind_of? String
47
+ fields = fields.split(',')
48
+ fields = fields.map {|f| f.strip}
49
+ end
50
+
51
+ values = fields.map {|v| v.to_sym}
52
+
53
+ query = "SELECT #{values.join(', ')} from #{sf_module}"
54
+ query(query, options.merge(:values => values))
55
+ end
56
+
57
+ def query(query, options)
58
+ values = options[:values]
59
+ as_hash = options[:as_hash]
60
+ counter = 1
61
+ fail "If you want to return array you need to specify fields in values key" if !as_hash && values.nil?
62
+
63
+ rforce_binding = @rforce_binding
64
+ output = options[:output]
65
+ begin
66
+ answer = rforce_binding.query({:queryString => query, :batchSize => 2000})
67
+ rescue Timeout::Error => e
68
+ puts "Timeout occured retrying"
69
+ retry
70
+ end
71
+
72
+ if answer[:queryResponse].nil? || answer[:queryResponse][:result].nil?
73
+ fail answer[:Fault][:faultstring] if answer[:Fault] && answer[:Fault][:faultstring]
74
+ fail "An unknown error occured while querying salesforce."
75
+ end
76
+
77
+ answer[:queryResponse][:result][:records].each {|row| output << (as_hash ? row : row.values_at(*values))} if answer[:queryResponse][:result][:size].to_i > 0
78
+
79
+ more_locator = answer[:queryResponse][:result][:queryLocator]
80
+
81
+ while more_locator do
82
+ answer_more = rforce_binding.queryMore({:queryLocator => more_locator, :batchSize => 2000})
83
+ answer_more[:queryMoreResponse][:result][:records].each do |row|
84
+ output << (as_hash ? row : row.values_at(*values))
85
+ end
86
+ more_locator = answer_more[:queryMoreResponse][:result][:queryLocator]
87
+ end
88
+ end
89
+
90
+ def get_deleted(options={})
91
+ rforce_binding = @rforce_binding
92
+ sf_module = options[:module]
93
+ end_time = options[:end_time] || Time.now
94
+ start_time = options[:start_time] || end_time.advance(:days => -15)
95
+ fail "The specified start_time cannot be the same value as, or later than, the specified end_time value" unless end_time > start_time
96
+ puts "Downloading from #{start_time} to #{end_time}"
97
+ answer = rforce_binding.getDeleted([:sObjectType, sf_module, :startDate, start_time.utc.iso8601, :endDate, end_time.utc.iso8601])
98
+ end
99
+
100
+ def download_deleted(options={})
101
+ output_file = options[:output_file]
102
+ fail "Output file not specified" if output_file.nil?
103
+
104
+ answer = get_deleted(options)
105
+ if answer[:getDeletedResponse].nil?
106
+ fail answer[:Fault][:faultstring] if answer[:Fault] && answer[:Fault][:faultstring]
107
+ fail "An unknown error occured during deleted records extraction."
108
+ end
109
+
110
+ result = answer[:getDeletedResponse][:result]
111
+ FasterCSV.open(output_file,"w") do |csv|
112
+ csv << ["Timestamp", "Id", "IsDeleted"]
113
+ unless result[:deletedRecords].nil? then
114
+ result[:deletedRecords].each do |record|
115
+ timestamp = Time.parse(record[:deletedDate]).to_i
116
+ csv << [timestamp, record[:id], "true"]
117
+ end
118
+ end
119
+ end
120
+
121
+ return result[:earliestDateAvailable], result[:latestDateCovered]
122
+ end
123
+
124
+ def download_updated(options={})
125
+ module_name = options[:module]
126
+ end_time = options[:end_time] || Time.now
127
+ start_time = options[:start_time] || end_time.advance(:days => -1)
128
+ fields_list = options[:fields] || []
129
+ puts "Downloading #{module_name} from #{start_time} to #{end_time}"
130
+ update_answer = rforce_binding.getUpdated([:sObjectType, module_name, :startDate, start_time.utc.iso8601, :endDate, end_time.utc.iso8601])
131
+ results = update_answer[:getUpdatedResponse][:result][:ids]
132
+ if results.nil?
133
+ puts "#{module_name} is empty"
134
+ FasterCSV.open(options[:output_file], 'w') do |csv|
135
+ csv << fields_list
136
+ end
137
+ return update_answer[:getUpdatedResponse][:result][:latestDateCovered]
138
+ end
139
+ puts "Found and downloaded #{results.size} records"
140
+ fields_list = fields_list.map {|x| x.strip.to_sym}
141
+
142
+ converters = {
143
+ "datetime" => lambda {|f| Time.parse(f).utc.to_i rescue f},
144
+ "string" => lambda {|f| f[0..128] rescue f},
145
+ "textarea" => lambda {|f| f[0..128] rescue f},
146
+ "date" => lambda {|f| Time.parse(f).utc.to_i + (12 * 3600) rescue f},
147
+ }
148
+
149
+ answer = describe(module_name)
150
+ fields_description = answer[:describeSObjectResponse][:result][:fields]
151
+ my_fields_description = fields_list.map {|f| fields_description.detect {|fl| fl[:name].to_sym == f}}
152
+
153
+ my_converters = my_fields_description.map {|fd| converters[fd[:type]]}
154
+ FasterCSV.open(options[:output_file], 'w') do |csv|
155
+ csv << ['Timestamp'] + fields_list
156
+ results.each_slice(2000) do |slice|
157
+ ids = slice.reduce([]) do |memo, item|
158
+ memo.concat [:ID, item]
159
+ end
160
+ result = rforce_binding.retrieve([:fieldList, fields_list.join(', '), :sObjectType, module_name].concat(ids) )
161
+ result[:retrieveResponse][:result].each do |line|
162
+
163
+ values = line.values_at(*fields_list).zip(my_converters).map do |value, converter|
164
+ converter.nil? ? value : converter.call(value)
165
+ end
166
+ csv << [Time.parse(update_answer[:getUpdatedResponse][:result][:latestDateCovered]).utc.to_i] + values
167
+ end
168
+ end
169
+ end
170
+ update_answer[:getUpdatedResponse][:result][:latestDateCovered]
171
+ end
172
+
173
+ end
174
+ end
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "salesforce/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "gd_salesforce"
7
+ s.version = Salesforce::VERSION
8
+ s.authors = ["Tomas Svarovsky"]
9
+ s.email = ["svarovsky.tomas@gmail.com"]
10
+ s.homepage = "https://github.com/fluke777/salesforce"
11
+ s.summary = %q{Small gem that wraps common tasks that I do with Salesforce}
12
+ s.description = %q{Small gem that wraps common tasks that I do with Salesforce}
13
+
14
+ s.rubyforge_project = "salesforce"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ s.add_runtime_dependency "rforce"
24
+ s.add_runtime_dependency "fastercsv"
25
+ s.add_runtime_dependency "activesupport"
26
+ s.add_runtime_dependency "pry"
27
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gd_salesforce
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tomas Svarovsky
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rforce
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: fastercsv
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: activesupport
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: pry
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: Small gem that wraps common tasks that I do with Salesforce
79
+ email:
80
+ - svarovsky.tomas@gmail.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - Gemfile
87
+ - README.markdown
88
+ - Rakefile
89
+ - lib/salesforce.rb
90
+ - lib/salesforce/version.rb
91
+ - salesforce.gemspec
92
+ homepage: https://github.com/fluke777/salesforce
93
+ licenses: []
94
+ post_install_message:
95
+ rdoc_options: []
96
+ require_paths:
97
+ - lib
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project: salesforce
112
+ rubygems_version: 1.8.25
113
+ signing_key:
114
+ specification_version: 3
115
+ summary: Small gem that wraps common tasks that I do with Salesforce
116
+ test_files: []