salesforce_bulk_query-edge 0.2.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.
@@ -0,0 +1,16 @@
1
+ require 'csv'
2
+
3
+ module SalesforceBulkQuery
4
+ class Utils
5
+ # record count if they want to
6
+ def self.line_count(f)
7
+ i = 0
8
+ CSV.foreach(f, :headers => true,:encoding => "UTF-8") {|_| i += 1}
9
+ i
10
+ end
11
+
12
+ def self.header(f)
13
+ File.open(f, &:readline).split(',').map{ |c| c.strip.delete('"') }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ module SalesforceBulkQuery
2
+ VERSION = '0.2.1'
3
+ end
@@ -0,0 +1,22 @@
1
+ #!/bin/sh
2
+
3
+ # get the new version
4
+ VERSION=`bundle exec ruby <<-EORUBY
5
+
6
+ require 'salesforce_bulk_query'
7
+ puts SalesforceBulkQuery::VERSION
8
+
9
+ EORUBY`
10
+
11
+ # create tag and push it
12
+ TAG="v$VERSION"
13
+ git tag $TAG
14
+ git push origin $TAG
15
+
16
+ # build and push the gem
17
+ gem build salesforce_bulk_query.gemspec
18
+ gem push "salesforce_bulk_query-$VERSION.gem"
19
+
20
+ # update the gem after a few secs
21
+ sleep 30
22
+ gem update salesforce_bulk_query
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib/", __FILE__)
3
+ require "salesforce_bulk_query/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'salesforce_bulk_query-edge'
7
+ s.version = SalesforceBulkQuery::VERSION
8
+ s.authors = ['Petr Cvengros']
9
+ s.email = ['petr.cvengros@gooddata.com']
10
+
11
+ s.required_ruby_version = '>= 1.9'
12
+
13
+ s.homepage = 'https://github.com/cvengros/salesforce_bulk_query'
14
+ s.summary = %q{Downloading data from Salesforce Bulk API made easy and scalable.}
15
+ s.description = %q{A library for downloading data from Salesforce Bulk API. We only focus on querying, other operations of the API aren't supported. Designed to handle a lot of data.}
16
+ s.license = 'BSD'
17
+
18
+ s.add_dependency 'json', '<= 2'
19
+ s.add_dependency 'xml-simple', '~> 1.1'
20
+
21
+ s.add_development_dependency 'multi_json', '~> 1.9'
22
+ s.add_development_dependency 'restforce', '~>1.4'
23
+ s.add_development_dependency 'rspec', '~>2.14'
24
+ s.add_development_dependency 'pry', '~>0.9'
25
+ s.add_development_dependency 'pry-stack_explorer', '~>0.4' if RUBY_PLATFORM != 'java'
26
+ s.add_development_dependency 'rake', '~> 10.3'
27
+ s.add_development_dependency 'coveralls', '~> 0.7'
28
+ s.add_development_dependency 'webmock', '~> 1.20'
29
+
30
+ s.files = `git ls-files`.split($/)
31
+ s.require_paths = ['lib']
32
+
33
+ s.rubygems_version = "1.3.7"
34
+ end
@@ -0,0 +1,227 @@
1
+ require 'multi_json'
2
+ require 'csv'
3
+ require 'tmpdir'
4
+ require 'logger'
5
+ require 'set'
6
+ require 'salesforce_bulk_query'
7
+ require 'restforce'
8
+ require 'webmock/rspec'
9
+
10
+ class Helper
11
+ DEFAULT_API_VERSION = '30.0'
12
+ def self.create_default_restforce
13
+ Restforce.new(
14
+ :username => ENV['USERNAME'],
15
+ :password => ENV['PASSWORD'],
16
+ :security_token => ENV['TOKEN'],
17
+ :client_id => ENV['CLIENT_ID'],
18
+ :client_secret => ENV['CLIENT_SECRET'],
19
+ :api_version => api_version
20
+ )
21
+ end
22
+
23
+ def self.api_version
24
+ ENV['API_VERSION'] || DEFAULT_API_VERSION
25
+ end
26
+
27
+ def self.create_default_api(restforce)
28
+ # switch off the normal logging
29
+ Restforce.log = false
30
+
31
+ SalesforceBulkQuery::Api.new(restforce,
32
+ :api_version => ENV['API_VERSION'] || DEFAULT_API_VERSION,
33
+ :logger => ENV['LOGGING'] ? Logger.new(STDOUT): nil
34
+ )
35
+ end
36
+ end
37
+
38
+ # test co nejak nafakuje tu situaci v twc
39
+ describe SalesforceBulkQuery do
40
+ before :all do
41
+ WebMock.allow_net_connect!
42
+
43
+ @client = Helper.create_default_restforce
44
+ @api = Helper.create_default_api(@client)
45
+ @entity = ENV['ENTITY'] || 'Opportunity'
46
+ @field_list = (ENV['FIELD_LIST'] || "Id,CreatedDate").split(',')
47
+ @api_version = Helper.api_version
48
+ end
49
+
50
+ describe "instance_url" do
51
+ it "gives you some reasonable url" do
52
+ url = @api.instance_url
53
+ url.should_not be_empty
54
+ url.should match(/salesforce\.com\//)
55
+ end
56
+ end
57
+
58
+ describe "query" do
59
+ context "if you give it an invalid SOQL" do
60
+ it "fails with argument error" do
61
+ expect{@api.query(@entity, "SELECT Id, SomethingInvalid FROM #{@entity}")}.to raise_error(ArgumentError)
62
+ end
63
+ end
64
+ context "when you give it no options" do
65
+ it "downloads the data to a few files", :constraint => 'slow' do
66
+ result = @api.query(@entity, "SELECT #{@field_list.join(', ')} FROM #{@entity}", :count_lines => true)
67
+ filenames = result[:filenames]
68
+ filenames.should have_at_least(2).items
69
+ result[:jobs_done].should_not be_empty
70
+
71
+ # no duplicate filenames
72
+ expect(Set.new(filenames).length).to eq(filenames.length)
73
+
74
+ filenames.each do |filename|
75
+ File.size?(filename).should be_true
76
+
77
+ lines = CSV.read(filename)
78
+
79
+ if lines.length > 1
80
+ # first line should be the header
81
+ lines[0].should eql(@field_list)
82
+
83
+ # first id shouldn't be emtpy
84
+ lines[1][0].should_not be_empty
85
+ end
86
+ end
87
+ end
88
+ end
89
+ context "when we want to mock things" do
90
+ before(:each) do
91
+ WebMock.allow_net_connect!
92
+ end
93
+ after(:each) do
94
+ WebMock.allow_net_connect!
95
+ end
96
+ it "catches the timeout error for query" do
97
+ # stub the timeout on query
98
+ host = URI.parse(@api.instance_url).host
99
+ query_url = "#{host}/services/data/v#{@api_version}/query"
100
+ query_regexp = Regexp.new(query_url)
101
+ # 4 timeouts (first get the oldest record), then fake a
102
+ # 0 count query response
103
+ stub_request(:get, query_regexp).to_timeout.times(4).then.to_return(
104
+ :body => "{\"totalSize\":0,\"done\":true,\"records\":[]}",
105
+ :headers => {
106
+ "date"=>"Wed, 04 Feb 2015 01:18:45 GMT",
107
+ "set-cookie"=>"BrowserId=hahaha;Path=/;Domain=.salesforce.com;Expires=never",
108
+ "expires"=>"Thu, 01 Jan 1970 00:00:00 GMT",
109
+ "sforce-limit-info"=>"api-usage=6666/15000",
110
+ "content-type"=>"application/json;charset=UTF-8",
111
+ "transfer-encoding"=>"chunked"}
112
+ )
113
+
114
+ # do the actual request
115
+ WebMock.allow_net_connect!
116
+ result = @api.query(
117
+ @entity,
118
+ "SELECT #{@field_list.join(', ')} FROM #{@entity}",
119
+ :count_lines => true,
120
+ :single_batch => true
121
+ )
122
+
123
+ # check it
124
+ expect(result[:succeeded]).to be_true
125
+ expect(result[:unfinished_subqueries]).to be_empty
126
+ expect(result[:filenames]).not_to be_empty
127
+ expect(result[:jobs_done]).not_to be_empty
128
+ end
129
+ end
130
+ context "when you give it all the options" do
131
+ it "downloads a single file" do
132
+ tmp = Dir.mktmpdir
133
+ frm = "2000-01-01"
134
+ from = "#{frm}T00:00:00.000Z"
135
+ t = "2020-01-01"
136
+ to = "#{t}T00:00:00.000Z"
137
+ field = 'SystemModstamp'
138
+ result = @api.query(
139
+ "Account",
140
+ "SELECT Id, Name, Industry, Type FROM Account",
141
+ :check_interval => 30,
142
+ :directory_path => tmp,
143
+ :date_from => from,
144
+ :date_to => to,
145
+ :single_batch => true,
146
+ :count_lines => true,
147
+ :date_field => field
148
+ )
149
+
150
+ result[:filenames].should have(1).items
151
+ result[:jobs_done].should_not be_empty
152
+
153
+ filename = result[:filenames][0]
154
+
155
+ File.size?(filename).should be_true
156
+ lines = CSV.read(filename)
157
+
158
+ # first line should be the header
159
+ lines[0].should eql(["Id", "Name", "Industry", "Type"])
160
+
161
+ # first id shouldn't be emtpy
162
+ lines[1][0].should_not be_empty
163
+
164
+ filename.should match(tmp)
165
+ filename.should match(frm)
166
+ filename.should match(t)
167
+ filename.should match(field)
168
+ end
169
+ end
170
+ context "when you give it a bad date_field" do
171
+ it "fails with argument error with no from date" do
172
+ expect{@api.query(@entity, "SELECT Id, CreatedDate FROM #{@entity}", :date_field => 'SomethingInvalid')}.to raise_error(ArgumentError)
173
+ end
174
+ it "fails with argument error with given from date" do
175
+ from = "2000-01-01T00:00:00.000Z"
176
+ expect{
177
+ @api.query(
178
+ @entity,
179
+ "SELECT Id, CreatedDate FROM #{@entity}",
180
+ :date_field => 'SomethingInvalid',
181
+ :date_from => from
182
+ )
183
+ }.to raise_error(ArgumentError)
184
+ end
185
+
186
+ end
187
+ context "when you give it a short time limit" do
188
+ it "downloads some stuff is unfinished" do
189
+ result = @api.query(
190
+ "Opportunity",
191
+ "SELECT Id, Name, CreatedDate FROM Opportunity",
192
+ :time_limit => 15
193
+ )
194
+ # one of them should be non-empty
195
+ expect((! result[:unfinished_subqueries].empty?) || (! result[:filenames].empty?)).to eq true
196
+ end
197
+ end
198
+ context "when you pass a short job time limit" do
199
+ it "creates quite a few jobs quickly", :skip => true do
200
+ # development only
201
+ result = @api.query(
202
+ @entity,
203
+ "SELECT Id, CreatedDate FROM #{@entity}",
204
+ :count_lines => true,
205
+ :job_time_limit => 60
206
+ )
207
+ require 'pry'; binding.pry
208
+ end
209
+ end
210
+ end
211
+
212
+ describe "start_query" do
213
+ it "starts a query that finishes some time later" do
214
+ query = @api.start_query("Opportunity", "SELECT Id, Name, CreatedDate FROM Opportunity", :single_batch => true)
215
+
216
+ # get a cofee
217
+ sleep(60*2)
218
+
219
+ # check the status
220
+ result = query.get_available_results
221
+ expect(result[:succeeded]).to eq true
222
+ result[:filenames].should have_at_least(1).items
223
+ result[:jobs_done].should_not be_empty
224
+ end
225
+
226
+ end
227
+ end
@@ -0,0 +1,9 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+
4
+ RSpec.configure do |c|
5
+ c.filter_run :focus => true
6
+ c.run_all_when_everything_filtered = true
7
+ c.filter_run_excluding :skip => true
8
+ end
9
+
metadata ADDED
@@ -0,0 +1,207 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: salesforce_bulk_query-edge
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Petr Cvengros
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-07-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "<="
18
+ - !ruby/object:Gem::Version
19
+ version: '2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "<="
25
+ - !ruby/object:Gem::Version
26
+ version: '2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: xml-simple
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: multi_json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: restforce
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.14'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.14'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.9'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.9'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry-stack_explorer
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.4'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.4'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '10.3'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '10.3'
125
+ - !ruby/object:Gem::Dependency
126
+ name: coveralls
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.7'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.7'
139
+ - !ruby/object:Gem::Dependency
140
+ name: webmock
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '1.20'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '1.20'
153
+ description: A library for downloading data from Salesforce Bulk API. We only focus
154
+ on querying, other operations of the API aren't supported. Designed to handle a
155
+ lot of data.
156
+ email:
157
+ - petr.cvengros@gooddata.com
158
+ executables: []
159
+ extensions: []
160
+ extra_rdoc_files: []
161
+ files:
162
+ - ".gitignore"
163
+ - ".rspec"
164
+ - ".travis.yml"
165
+ - Gemfile
166
+ - LICENSE
167
+ - README.md
168
+ - Rakefile
169
+ - env_setup-example.sh
170
+ - lib/salesforce_bulk_query.rb
171
+ - lib/salesforce_bulk_query/batch.rb
172
+ - lib/salesforce_bulk_query/connection.rb
173
+ - lib/salesforce_bulk_query/job.rb
174
+ - lib/salesforce_bulk_query/logger.rb
175
+ - lib/salesforce_bulk_query/query.rb
176
+ - lib/salesforce_bulk_query/utils.rb
177
+ - lib/salesforce_bulk_query/version.rb
178
+ - new-version.sh
179
+ - salesforce_bulk_query.gemspec
180
+ - spec/salesforce_bulk_query_spec.rb
181
+ - spec/spec_helper.rb
182
+ homepage: https://github.com/cvengros/salesforce_bulk_query
183
+ licenses:
184
+ - BSD
185
+ metadata: {}
186
+ post_install_message:
187
+ rdoc_options: []
188
+ require_paths:
189
+ - lib
190
+ required_ruby_version: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '1.9'
195
+ required_rubygems_version: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - ">="
198
+ - !ruby/object:Gem::Version
199
+ version: '0'
200
+ requirements: []
201
+ rubyforge_project:
202
+ rubygems_version: 2.6.8
203
+ signing_key:
204
+ specification_version: 4
205
+ summary: Downloading data from Salesforce Bulk API made easy and scalable.
206
+ test_files: []
207
+ has_rdoc: