gd_salesforce 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []