gd_bam 0.1.14 → 0.1.15

Sign up to get free protection for your applications and to get access to all the features.
data/lib/bam/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Bam
2
- VERSION = '0.1.14'
2
+ VERSION = '0.1.15'
3
3
  end
@@ -378,72 +378,81 @@ HEREDOC
378
378
  builder.Phase(:number => phase += 1) do
379
379
 
380
380
  f = field[:name]
381
- selects = objects_to_get.reduce([]) do |memo, o|
382
- fields = client.fields(o)
383
- generic_field_history = ["NewValue", "OldValue", "ParentId"].all? {|fl| fields.include?(fl)}
384
- specific_field_history = ["NewValue", "OldValue", "#{sf_object}Id"].all? {|fl| fields.include?(fl)}
385
- specific_history = ["CreatedDate", "#{sf_object}Id"].all? {|fl| fields.include?(fl)}
386
-
387
- select, mapping, mandatory = if generic_field_history
388
- [
389
- "SELECT NewValue, CreatedDate, ParentId FROM #{o} WHERE Field = '#{f}'",
390
- "{\"xmlFieldsMapping\":{\"xmlFields\":[
391
- {\"xmlFieldMapping\":{\"name\":\"NewValue\",\"label\":\"NewValue\",\"xmlPath\":\"NewValue\",\"metadataField\":\"Value\"}},
392
- {\"xmlFieldMapping\":{\"name\":\"CreatedDate\",\"label\":\"CreatedDate\",\"xmlPath\":\"CreatedDate\",\"metadataField\":\"Timestamp\"}},
393
- {\"xmlFieldMapping\":{\"name\":\"ParentId\",\"label\":\"ParentId\",\"xmlPath\":\"ParentId\",\"metadataField\":\"Id\"}}
394
- ]}}",
395
- ["ParentId", "NewValue", "CreatedDate"]
396
- ]
397
- elsif specific_field_history
398
- [
399
- "SELECT NewValue, CreatedDate, #{sf_object}Id FROM #{o} WHERE Field = '#{f}'",
400
- "{\"xmlFieldsMapping\":{\"xmlFields\":[
401
- {\"xmlFieldMapping\":{\"name\":\"NewValue\",\"label\":\"NewValue\",\"xmlPath\":\"NewValue\",\"metadataField\":\"Value\"}},
402
- {\"xmlFieldMapping\":{\"name\":\"CreatedDate\",\"label\":\"CreatedDate\",\"xmlPath\":\"CreatedDate\",\"metadataField\":\"Timestamp\"}},
403
- {\"xmlFieldMapping\":{\"name\":\"#{sf_object}Id\",\"label\":\"#{sf_object}Id\",\"xmlPath\":\"#{sf_object}Id\",\"metadataField\":\"Id\"}}
404
- ]}}",
405
- ["#{sf_object}Id", "NewValue", "CreatedDate"]
406
- ]
407
- elsif specific_history
408
- if f == "CreatedDate"
381
+ selects = if (f == "CreatedDate") then
382
+ [{
383
+ :object => sf_object,
384
+ :query => "SELECT Id, CreatedDate FROM #{sf_object}",
385
+ :mapping => "{\"xmlFieldsMapping\":{\"xmlFields\":[
386
+ {\"xmlFieldMapping\":{\"name\":\"CreatedDate\",\"label\":\"CreatedDate\",\"xmlPath\":\"CreatedDate\",\"metadataField\":\"Value\"}},
387
+ {\"xmlFieldMapping\":{\"name\":\"CreatedDate\",\"label\":\"CreatedDate\",\"xmlPath\":\"CreatedDate\",\"metadataField\":\"Timestamp\"}},
388
+ {\"xmlFieldMapping\":{\"name\":\"Id\",\"label\":\"Id\",\"xmlPath\":\"Id\",\"metadataField\":\"Id\"}}
389
+ ]}}",
390
+ :mandatory => ["Id", "CreatedDate"]
391
+ }]
392
+ # binding.pry
393
+ # temp
394
+ else
395
+ objects_to_get.reduce([]) do |memo, o|
396
+ fields = client.fields(o)
397
+ # how the history is stored does not rely on table naming convention. It is a couple of conventionsmangled together.This piece of code is trying to recognize which it is and produce the right downloader
398
+ generic_field_history = ["NewValue", "OldValue", "ParentId"].all? {|fl| fields.include?(fl)}
399
+ specific_field_history = ["NewValue", "OldValue", "#{sf_object}Id"].all? {|fl| fields.include?(fl)}
400
+ specific_history = ["CreatedDate", "#{sf_object}Id"].all? {|fl| fields.include?(fl)}
401
+
402
+ select, mapping, mandatory = if generic_field_history
403
+ # This kicks in when you have Field History type of table. There are several versions in SF. This one deals with the one that references ID of the record as Pernt Id. This is not true for opportunity, account.
409
404
  [
410
- "SELECT CreatedDate, #{sf_object}Id FROM #{o}",
405
+ "SELECT NewValue, CreatedDate, ParentId FROM #{o} WHERE Field = '#{f}'",
411
406
  "{\"xmlFieldsMapping\":{\"xmlFields\":[
412
- {\"xmlFieldMapping\":{\"name\":\"CreatedDate\",\"label\":\"CreatedDate\",\"xmlPath\":\"CreatedDate\",\"metadataField\":\"Value\"}},
407
+ {\"xmlFieldMapping\":{\"name\":\"NewValue\",\"label\":\"NewValue\",\"xmlPath\":\"NewValue\",\"metadataField\":\"Value\"}},
413
408
  {\"xmlFieldMapping\":{\"name\":\"CreatedDate\",\"label\":\"CreatedDate\",\"xmlPath\":\"CreatedDate\",\"metadataField\":\"Timestamp\"}},
414
- {\"xmlFieldMapping\":{\"name\":\"#{sf_object}Id\",\"label\":\"#{sf_object}Id\",\"xmlPath\":\"#{sf_object}Id\",\"metadataField\":\"Id\"}}
409
+ {\"xmlFieldMapping\":{\"name\":\"ParentId\",\"label\":\"ParentId\",\"xmlPath\":\"ParentId\",\"metadataField\":\"Id\"}}
415
410
  ]}}",
416
- ["#{sf_object}Id", "CreatedDate"]
411
+ ["ParentId", "NewValue", "CreatedDate"]
417
412
  ]
418
- elsif fields.include?(f)
413
+ elsif specific_field_history
414
+ # This is like the previous with the difference that it specifically names the id of the record. Like OpportunityId, AccountId, etc.
419
415
  [
420
- "SELECT #{f}, CreatedDate, #{sf_object}Id FROM #{o}",
416
+ "SELECT NewValue, CreatedDate, #{sf_object}Id FROM #{o} WHERE Field = '#{f}'",
421
417
  "{\"xmlFieldsMapping\":{\"xmlFields\":[
422
- {\"xmlFieldMapping\":{\"name\":\"#{f}\",\"label\":\"#{f}\",\"xmlPath\":\"#{f}\",\"metadataField\":\"Value\"}},
418
+ {\"xmlFieldMapping\":{\"name\":\"NewValue\",\"label\":\"NewValue\",\"xmlPath\":\"NewValue\",\"metadataField\":\"Value\"}},
423
419
  {\"xmlFieldMapping\":{\"name\":\"CreatedDate\",\"label\":\"CreatedDate\",\"xmlPath\":\"CreatedDate\",\"metadataField\":\"Timestamp\"}},
424
420
  {\"xmlFieldMapping\":{\"name\":\"#{sf_object}Id\",\"label\":\"#{sf_object}Id\",\"xmlPath\":\"#{sf_object}Id\",\"metadataField\":\"Id\"}}
425
421
  ]}}",
426
- ["#{sf_object}Id", f, "CreatedDate"]
422
+ ["#{sf_object}Id", "NewValue", "CreatedDate"]
427
423
  ]
424
+ elsif specific_history
425
+ # Specific history is the row like history. The only instance I know of is OpportunityHistory.
426
+ if fields.include?(f)
427
+ [
428
+ "SELECT #{f}, CreatedDate, #{sf_object}Id FROM #{o}",
429
+ "{\"xmlFieldsMapping\":{\"xmlFields\":[
430
+ {\"xmlFieldMapping\":{\"name\":\"#{f}\",\"label\":\"#{f}\",\"xmlPath\":\"#{f}\",\"metadataField\":\"Value\"}},
431
+ {\"xmlFieldMapping\":{\"name\":\"CreatedDate\",\"label\":\"CreatedDate\",\"xmlPath\":\"CreatedDate\",\"metadataField\":\"Timestamp\"}},
432
+ {\"xmlFieldMapping\":{\"name\":\"#{sf_object}Id\",\"label\":\"#{sf_object}Id\",\"xmlPath\":\"#{sf_object}Id\",\"metadataField\":\"Id\"}}
433
+ ]}}",
434
+ ["#{sf_object}Id", f, "CreatedDate"]
435
+ ]
436
+ else
437
+ [nil, nil, nil]
438
+ end
428
439
  else
429
- [nil, nil]
440
+ fail "Unrecognized fields configuration for historization in SF."
441
+ end
442
+ if select.nil?
443
+ memo
444
+ else
445
+ memo.concat([{
446
+ :object => o,
447
+ :query => select,
448
+ :mapping => mapping,
449
+ :mandatory => mandatory
450
+ }])
430
451
  end
431
- else
432
- fail "Unrecognized fields configuration for historization in SF."
433
- end
434
- if select.nil?
435
- memo
436
- else
437
- memo.concat([{
438
- :object => o,
439
- :query => select,
440
- :mapping => mapping,
441
- :mandatory => mandatory
442
- }])
443
452
  end
444
453
  end
445
-
446
454
  unless selects.empty?
455
+ # binding.pry if f== "CreatedDate"
447
456
  taps_with_history.concat([tap])
448
457
  selects = selects.concat([{
449
458
  :object => sf_object,
@@ -456,15 +465,15 @@ HEREDOC
456
465
  :mandatory => ["Id", f, "SystemModstamp"]
457
466
  }])
458
467
  selects.each_with_index do |obj, i|
459
-
468
+ # binding.pry if f== "CreatedDate"
460
469
  o = obj[:object]
461
470
  mapping = obj[:mapping]
462
471
  select = obj[:query]
463
472
  mandatory = obj[:mandatory]
464
473
  # puts "#{f}_#{o}_reader:0 -> #{f}_#{sf_object}_gather:#{i}"
465
474
 
466
- Core::build_node2(builder, Nodes.sfdc_reader2({:name => "#{o} SF Reader #{i}", :id => "#{f}_#{o}_reader", :soql => select, :sfdcConnection => "SFDC", :fieldsMapping => mapping, :mandatoryFields => mandatory.join(';')}))
467
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{f}_#{sf_object}_gather:#{i}", :fromNode => "#{f}_#{o}_reader:0", :metadata => "data_metadata"}))
475
+ Core::build_node2(builder, Nodes.sfdc_reader2({:name => "#{o} SF Reader #{i}", :id => "#{f}_#{o}_#{i}_reader", :soql => select, :sfdcConnection => "SFDC", :fieldsMapping => mapping, :mandatoryFields => mandatory.join(';')}))
476
+ Core::build_node2(builder, Nodes.edge2({:toNode => "#{f}_#{sf_object}_gather:#{i}", :fromNode => "#{f}_#{o}_#{i}_reader:0", :metadata => "data_metadata"}))
468
477
  end
469
478
  Core::build_node2(builder, Nodes.gather2({:name => "#{f} Gather", :id => "#{f}_#{sf_object}_gather"}))
470
479
  Core::build_node2(builder, Nodes.sort2({:sortKey => "Timestamp(a)",:name => "#{f}_#{sf_object}_sort", :id => "#{f}_#{sf_object}_sort"}))
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gd_bam
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.14
4
+ version: 0.1.15
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-17 00:00:00.000000000 Z
12
+ date: 2013-07-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -308,7 +308,6 @@ extra_rdoc_files:
308
308
  - README.md
309
309
  files:
310
310
  - bin/bam
311
- - bin/bam.orig
312
311
  - lib/bam/version.rb
313
312
  - lib/bam.rb
314
313
  - lib/base/errors.rb
@@ -339,7 +338,6 @@ files:
339
338
  - lib/compiler/etl_visitor.rb
340
339
  - lib/dsl/dsl.rb
341
340
  - lib/generators/downloaders.rb
342
- - lib/generators/downloaders.rb.orig
343
341
  - lib/generators/etl.rb
344
342
  - lib/generators/validators.rb
345
343
  - lib/graphs/docentize.grf
data/bin/bam.orig DELETED
@@ -1,375 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'gli'
3
- require 'bam'
4
-
5
- include GLI::App
6
-
7
- program_desc 'Describe your application here'
8
-
9
- version Bam::VERSION
10
-
11
- # desc 'Describe some switch here'
12
- # switch [:s,:switch]
13
- #
14
- desc 'Verbose'
15
- default_value false
16
- arg_name 'verbose'
17
- switch [:v,:verbose]
18
-
19
- desc 'Http logger'
20
- default_value false
21
- arg_name 'logger'
22
- switch [:l,:logger]
23
-
24
- desc 'Generates clover project based on information in current directory. The default ouptut is the directory ./clover-project'
25
- # arg_name 'Describe arguments to new here'
26
- command :generate do |c|
27
-
28
- c.desc 'generate only specified flow'
29
- c.arg_name 'only'
30
- c.flag :only
31
-
32
- c.action do |global_options,options,args|
33
- params = PARAMS.merge(options).merge({
34
- :project_name => "etl-#{PARAMS[:project_name]}",
35
- :graph_repos => [
36
- GoodData::Bam::Repository.create(:type => :file, :base => Pathname('./local_graphs').expand_path),
37
- GoodData::Bam::Repository.create(:type => :file, :base => GoodData::CloverGenerator::BAM_DEFINED_GRAPHS_ROOT)
38
- ]})
39
- GoodData::Bam::Commands::generate('.', params)
40
- end
41
- end
42
-
43
- desc 'Jacks into SF.'
44
- # arg_name 'Describe arguments to new here'
45
- command :sf_jack_in do |c|
46
-
47
- c.action do |global_options,options,args|
48
- GoodData::Bam::Commands::sf_jack_in(PARAMS)
49
- end
50
- end
51
-
52
- # desc 'Jacks into project.'
53
- # # arg_name 'Describe arguments to new here'
54
- # command :project_jack_in do |c|
55
- #
56
- # c.action do |global_options,options,args|
57
- # GoodData::Bam::Commands::project_jack_in(PARAMS)
58
- # end
59
- # end
60
-
61
-
62
- desc 'Validatates connection to SalesForce.'
63
- # arg_name 'Describe arguments to new here'
64
- command :sf_validate_connection do |c|
65
-
66
- c.action do |global_options,options,args|
67
- GoodData::Bam::Commands::sf_validate_connection(PARAMS)
68
- end
69
- end
70
-
71
-
72
- desc 'Generate data validator.'
73
- # arg_name 'Describe arguments to new here'
74
- command :generate_validator do |c|
75
- c.action do |global_options,options,args|
76
- GoodData::Bam::Commands::generate_validators('.', PARAMS.merge(options).merge({
77
- :project_name => "validator-#{PARAMS[:project_name]}",
78
- :graph_repos => [
79
- GoodData::Bam::Repository.create(:type => :file, :base => './local_graphs'),
80
- GoodData::Bam::Repository.create(:type => :file, :base => GoodData::CloverGenerator::BAM_DEFINED_GRAPHS_ROOT)
81
- ]
82
- }))
83
- end
84
- end
85
-
86
- desc 'Run data validator.'
87
- # arg_name 'Describe arguments to new here'
88
- command :run_validator do |c|
89
-
90
- c.desc 'Checker process ID'
91
- c.arg_name 'process'
92
- c.flag :process
93
-
94
- c.action do |global_options,options,args|
95
- process = options[:process]
96
- files = args.map {|f| Pathname(f)}
97
- files.each do |f|
98
- fail "Provded file \"#{f}\" does not exist." unless File.exist?(f)
99
- end
100
- fail "You need to specify process" if process.blank?
101
-
102
- GoodData::Bam::Commands::connect_to_gd()
103
- GoodData::Bam::Commands::run_validator(process, files, PARAMS)
104
- end
105
- end
106
-
107
-
108
- desc 'Generates clover project for downloaders.'
109
- # arg_name 'Describe arguments to new here'
110
- command :generate_downloaders do |c|
111
-
112
- c.desc 's3 backup'
113
- c.arg_name 'backup'
114
- c.flag :backup
115
-
116
- c.action do |global_options,options,args|
117
- params = global_options[:user_params]
118
- params = PARAMS.merge({
119
- :project_name => "downloaders-#{PARAMS[:project_name]}",
120
- :graph_repos => [
121
- GoodData::Bam::Repository.create(:type => :file, :base => './local_graphs'),
122
- GoodData::Bam::Repository.create(:type => :file, :base => GoodData::CloverGenerator::BAM_DEFINED_GRAPHS_ROOT)]
123
- })
124
- GoodData::Bam::Commands::generate_downloaders(".", params)
125
- end
126
- end
127
-
128
- command :generate_history_downloaders do |c|
129
-
130
- c.desc 's3 backup'
131
- c.arg_name 'backup'
132
- c.flag :backup
133
-
134
- c.action do |global_options,options,args|
135
- params = global_options[:user_params]
136
- params = PARAMS.merge({
137
- :project_name => "downloaders-#{PARAMS[:project_name]}",
138
- :graph_repos => [
139
- GoodData::Bam::Repository.create(:type => :file, :base => './local_graphs'),
140
- GoodData::Bam::Repository.create(:type => :file, :base => GoodData::CloverGenerator::BAM_DEFINED_GRAPHS_ROOT)]
141
- })
142
- <<<<<<< HEAD
143
- GoodData::Bam::Commands::generate_downloaders(".", params)
144
- =======
145
- GoodData::Bam::Commands::generate_history_downloaders(".", params)
146
- >>>>>>> Added historical SF downloader
147
- end
148
- end
149
-
150
-
151
-
152
- desc 'Validates that the tap has the fields it is claimed it should have. This is supposed to make the mitigate errors during deploy.'
153
- # arg_name 'Describe arguments to new here'
154
- command :sf_taps_validate do |c|
155
- c.action do |global_options,options,args|
156
- verbose = global_options[:v]
157
- params = PARAMS.merge({
158
- :graph_repos => [
159
- GoodData::Bam::Repository.create(:type => :file, :base => './local_graphs'),
160
- GoodData::Bam::Repository.create(:type => :file, :base => GoodData::CloverGenerator::BAM_DEFINED_GRAPHS_ROOT)]})
161
- result = GoodData::Bam::Commands::validate_sf_taps(params)
162
-
163
- error = false
164
- result.each_pair do |obj, fields|
165
- if fields.empty?
166
- puts HighLine::color("GOOD", :green) + " #{obj}"
167
- else
168
- error = true
169
- puts HighLine::color("BAD", :red) + " #{obj} [" + fields.join(', ') + "]"
170
- end
171
- end
172
- exit_now!("Errors found",exit_code=1) if error
173
- end
174
- end
175
-
176
- desc "Prepares params.prm file for debugging that particular graph"
177
- command :debug do |c|
178
- c.action do |global_options,options,args|
179
- fail "Arguments should be passed as \"project\" \"flow\" \"graph\"" if args.length < 3
180
- GoodData::Bam::Commands::set_up_debug(args.first, args[1], args[2])
181
- end
182
- end
183
-
184
- desc 'Validates that the tap has the fields it is claimed it should have. This is supposed to make the mitigate errors during deploy.'
185
- # arg_name 'Describe arguments to new here'
186
- command :docs do |c|
187
- c.action do |global_options,options,args|
188
- GoodData::Bam::Commands::generate_docs
189
- end
190
- end
191
-
192
- desc 'Lists processes for the project.'
193
- # arg_name 'Describe arguments to new here'
194
- command :procs do |c|
195
-
196
- c.desc 'procs for all projects'
197
- c.arg_name 'all'
198
- c.switch :all
199
-
200
- c.action do |global_options,options,args|
201
- out = GoodData::Bam::Commands::procs_list(options)
202
- out.each do |proc|
203
- puts proc.join(',')
204
- end
205
- end
206
- end
207
-
208
-
209
- desc 'Creates project'
210
- command :project do |c|
211
-
212
- c.desc 'blueprint name. Currently support goodsales'
213
- c.arg_name 'blueprint'
214
- c.flag :blueprint
215
-
216
- c.desc 'token'
217
- c.arg_name 'token'
218
- c.flag :token
219
-
220
- c.action do |global_options,options,args|
221
- fail "You need to specify token to create a project" if options[:token].nil?
222
-
223
- GoodData::Bam::Commands::connect_to_gd()
224
- pid = case options[:blueprint]
225
- when "goodsales"
226
- "nt935rwzls50zfqwy6dh62tabu8h0ocy"
227
- end
228
-
229
- params = PARAMS.merge({:token => options[:token]})
230
-
231
- new_project = if pid
232
- GoodData::Bam::Commands.clone_project(pid, params)
233
- else
234
- GoodData::Bam::Commands.create_project(params)
235
- end
236
-
237
- puts "Your project pid is #{new_project}"
238
- end
239
-
240
- end
241
-
242
-
243
- desc 'Generates structures'
244
- arg_name 'what you want to generate project, tap, flow, sink'
245
- command :scaffold do |c|
246
-
247
- c.desc 'blueprint name. Currently support goodsales'
248
- c.arg_name 'blueprint'
249
- c.flag :blueprint
250
-
251
- c.action do |global_options,options,args|
252
- command = args.first
253
- fail "You did not provide what I should scaffold. I can generate project, tap, flow, sink, graph_template nothing else" unless ["project", "tap", "flow", "sink", "graph_template"].include?(command)
254
- case command
255
- when "project"
256
- directory = args[1]
257
- fail "Directory has to be provided as an argument. See help" if directory.nil?
258
- if options[:blueprint].nil?
259
- GoodData::Bam::Commands::setup_bash_structure(directory)
260
- else
261
- case options[:blueprint]
262
- when "goodsales"
263
- system "git clone git://github.com/gooddata/goodsales_base.git #{directory}"
264
- end
265
- end
266
- when "flow"
267
- name = args[1]
268
- fail "Name of the flow has to be provided as an argument. See help" if name.nil?
269
- GoodData::Bam::Commands::setup_flow(name)
270
- when "tap"
271
- name = args[1]
272
- fail "Name of the tap has to be provided as an argument. See help" if name.nil?
273
- GoodData::Bam::Commands::setup_tap(name)
274
- when "sink"
275
- name = args[1]
276
- fail "Name of the sink has to be provided as an argument. See help" if name.nil?
277
- GoodData::Bam::Commands::setup_sink(name)
278
- when "graph_template"
279
- name = args[1]
280
- target = args[2]
281
- fail "Name of the template has to be provided as an argument. See help" if name.nil?
282
- fail "Name of the target has to be provided as an argument. See help" if target.nil?
283
- GoodData::Bam::Commands::generate_graph_template(name, target)
284
- end
285
- end
286
- end
287
-
288
- desc 'Runs the project on server'
289
- command :model_sync do |c|
290
-
291
- c.desc 'do not execute'
292
- c.arg_name 'dry'
293
- c.switch :dry
294
-
295
- c.action do |global_options,options,args|
296
- GoodData::Bam::Commands::model_sync('.', options)
297
- end
298
- end
299
-
300
-
301
- desc 'Deploys the project on server and schedules it'
302
- command :deploy do |c|
303
-
304
- c.desc 'existing process id under which it is going to be redeployed'
305
- c.arg_name 'process'
306
- c.flag :process
307
-
308
- c.desc 'name of the process'
309
- c.arg_name 'name'
310
- c.flag :name
311
-
312
- c.action do |global_options,options,args|
313
- dir = args.first
314
- fail "You have to specify directory to deploy as an argument" if dir.nil?
315
- fail "Specified directory does not exist" unless File.exist?(dir)
316
-
317
- GoodData::Bam::Commands::connect_to_gd()
318
- params = PARAMS.merge(global_options.merge(options))
319
- response = GoodData::Bam::Commands::deploy(dir, params)
320
- end
321
- end
322
-
323
- desc 'Runs the project on server'
324
- command :run do |c|
325
-
326
- c.desc 'email to addresses when the run is finished'
327
- c.arg_name 'email'
328
- c.flag :email
329
-
330
- c.action do |global_options,options,args|
331
-
332
- dir = args.first
333
- fail "You have to specify directory to deploy as an argument" if dir.nil?
334
- fail "Specified directory does not exist" unless File.exist?(dir)
335
-
336
- params = PARAMS.merge(global_options.merge(options))
337
- GoodData::Bam::Commands::connect_to_gd()
338
- GoodData::Bam::Commands::run(dir, params)
339
- end
340
- end
341
-
342
-
343
- pre do |global_options,command,options,args|
344
-
345
- logger = Logger.new(STDOUT) if global_options[:l]
346
- GoodData.logger = logger
347
- params = GoodData::Bam::Utils::get_user_params('.')
348
- s3_backup = GoodData::Bam::Utils::should_backup_to_s3?(params)
349
- PARAMS = params.merge({:s3_backup => s3_backup})
350
-
351
- # Pre logic here
352
- # Return true to proceed; false to abort and not call the
353
- # chosen command
354
- # Use skips_pre before a command to skip this block
355
- # on that command only
356
-
357
- true
358
- end
359
-
360
- post do |global_options,command,options,args|
361
- # Post logic here
362
- # Use skips_post before a command to skip this
363
- # block on that command only
364
- verbose = global_options[:v]
365
- puts HighLine::color("DONE", :green) if verbose
366
- end
367
-
368
- on_error do |exception|
369
- pp exception.backtrace
370
- # Error logic here
371
- # return false to skip default error handling
372
- true
373
- end
374
-
375
- exit run(ARGV)
@@ -1,663 +0,0 @@
1
- module GoodData
2
- module Bam
3
- module Generators
4
- module Downloaders
5
-
6
- include GoodData::Bam
7
- include GoodData::CloudConnect
8
-
9
- def self.create_incremental_downloader_run_graph(file, taps, options={})
10
-
11
- File.open(file, "w") do |file|
12
- builder = Builder::XmlMarkup.new(:target=>file, :indent=>2)
13
- builder.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
14
- builder.Graph({
15
- :name => "Run graph"
16
- }) do
17
- builder.Global do
18
- Helpers::property_file(builder, {:id => "workspace_params", :fileURL => "workspace.prm"})
19
- Helpers::property_file(builder, {:id => "params_params", :fileURL => "params.prm"})
20
- Helpers::create_trash_meta(builder)
21
- Helpers::create_lookup_meta(builder)
22
- Helpers::create_file_list_meta(builder)
23
- Helpers::create_run_graph_failure_metadata(builder)
24
-
25
- Core::build_node2(builder, Nodes.lookup2({:name => "gdLookup0", :id => "gdLookup0", :type => Nodes::GD_LOOKUP, :metadata => "lookup_metadata"}))
26
-
27
- end
28
- phase = 0
29
- sf_taps = Taps.get_salesforce(taps)
30
-
31
- sf_taps.each do |tap|
32
- module_name = tap[:object]
33
- file = tap[:id] || module_name
34
- dataset = file || module_name
35
-
36
-
37
- normalize_code = <<HEREDOC
38
- boolean done = false;
39
- function integer count() {
40
-
41
- if (indexOf($in.0.key, "#{dataset}_LAST_RUN") != -1) {
42
- return 4;
43
- }
44
- else {
45
- return 0;
46
- }
47
- }
48
-
49
- string last_run = null;
50
- string end_date = null;
51
-
52
- function integer transform(integer idx) {
53
- if (last_run == null) {
54
- last_run = $in.0.value;
55
- }
56
- if (end_date == null) {
57
- end_date = jodaDate2str(today(), "yyyy-MM-dd'T'HH:mm:ss.SSSZZ", "en_US", 'UTC');
58
- }
59
-
60
-
61
- if (idx == 1) {
62
- $out.0.all = "#{dataset}_TRUNCATE_DATE=" + jodaDate2str(jodaStr2date(last_run, ["yyyy-MM-dd'T'HH:mm:ss.SSSZZ"], 'en_US', 'UTC', 'UTC'), "yyyy-MM-dd HH:mm:ss", 'en_US', 'UTC');
63
- } else if (idx == 2) {
64
- $out.0.all = "#{dataset}_START=" + last_run;
65
- } else if (idx == 3) {
66
- $out.0.all = "#{dataset}_END=" + end_date;
67
- } else {
68
- $out.0.all = "#{dataset}_LAST_RUN=" + end_date;
69
- }
70
-
71
- return OK;
72
- }
73
-
74
- HEREDOC
75
-
76
-
77
-
78
-
79
- builder.Phase(:number => phase += 1) do
80
- generate_func = <<HEREDOC
81
- function integer generate() {
82
- $out.0.key = "#{dataset}_LAST_RUN";
83
- $out.0.value = "1970-01-01T00:00:00.000+00:00";
84
- return OK;
85
- }
86
- HEREDOC
87
-
88
- join_func = <<HEREDOC
89
- function integer transform() {
90
- $out.0.key = nvl2($in.1.value, $in.1.key, $in.0.key);
91
- $out.0.value = nvl2($in.1.value, $in.1.value, $in.0.value);
92
- return OK;
93
- }
94
- HEREDOC
95
-
96
- Core::build_node2(builder, Nodes.data_generator2({:name => "generator_#{dataset}", :id => "generator_#{dataset}", :generate => generate_func}))
97
- Core::build_node2(builder, Nodes.lookup_reader_writer2({:lookupTable => "gdLookup0", :id => "gd_lookup_reader_#{dataset}" }))
98
- Core::build_node2(builder, Nodes.hash_join2({:id => "join_#{dataset}", :joinType => "leftOuter", :joinKey => "$key=$key", :transformation => join_func}))
99
-
100
- Core::build_node2(builder, Nodes.edge2({:toNode => "join_#{dataset}:0", :fromNode => "generator_#{dataset}:0", :metadata => "lookup_metadata"}))
101
- Core::build_node2(builder, Nodes.edge2({:toNode => "join_#{dataset}:1", :fromNode => "gd_lookup_reader_#{dataset}:0", :metadata => "lookup_metadata"}))
102
-
103
- Core::build_node2(builder, Nodes.normalizer2({:name => "normalizer_#{dataset}", :id => "normalizer_#{dataset}", :normalize => normalize_code }))
104
- Core::build_node2(builder, Nodes.edge2({:toNode => "normalizer_#{dataset}:0", :fromNode => "join_#{dataset}:0", :metadata => "lookup_metadata"}))
105
-
106
- Core::build_node2(builder, Nodes.writer2({:quotedStrings => "false", :name => "params_writer_#{dataset}", :id => "params_writer_#{dataset}", :fileURL => "params.prm", :outputFieldNames => "false", :append => "true"}))
107
- Core::build_node2(builder, Nodes.edge2({:toNode => "params_writer_#{dataset}:0", :fromNode => "normalizer_#{dataset}:0", :metadata => "trash_metadata"}))
108
- end
109
- end
110
- builder.Phase(:number => phase += 1) do
111
- if !sf_taps.empty?
112
- Core::build_node2(builder, Nodes.run_graph2({:guiName => "incremental", :name => "incremental_downloaders", :id => "downlaoders", :graphName => "graphs/incremental.grf"}))
113
- end
114
- end
115
-
116
- file_taps = Taps.get_file(taps)
117
-
118
- file_taps.each do |tap|
119
- source = tap[:source]
120
- id = tap[:id]
121
-
122
-
123
- reformat_func = <<HEREDOC
124
-
125
- function integer transform() {
126
- $out.0.filePath = replace($in.0.filePath, "${GDC_WEBDAV_HOST}", replace(replace(\"${GD_LOGIN}\",\"@\",\"%40\"),\"\\\\+\",\"%2B\") + ":${GD_PASSWORD}@${GDC_WEBDAV_HOST}");
127
- $out.0.fileName = $in.0.fileName;
128
- return ALL;
129
- }
130
- HEREDOC
131
-
132
- builder.Phase(:number => phase += 1) do
133
- Core::build_node2(builder, Nodes.file_list2({:id => "#{id}_file_list", :name => "#{id}_file_list", :dataPolicy => "Strict", :baseURL => "#{tap[:source]}", :output_mapping => Nodes::MAP_ALL}))
134
- Core::build_node2(builder, Nodes.reformat2({:name => "#{id} Reformat", :id => "#{id}_reformat", :transformation => reformat_func}))
135
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{id}_reformat:0", :fromNode => "#{id}_file_list:0", :metadata => "file_list"}))
136
- Core::build_node2(builder, Nodes.writer2({:name => "PARAMS CSV Writer", :id => "#{id}_writer", :fileURL => "data/#{id}_files_to_read.csv"}))
137
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{id}_writer:0", :fromNode => "#{id}_reformat:0", :metadata => "file_list"}))
138
- end
139
-
140
- builder.Phase(:number => phase += 1) do
141
- ctl = "function integer generate() {$out.0.all = \"#{id}_SKIP_LINES=0\";return OK;}"
142
- Core::build_node2(builder, Nodes.data_generator2({:name => "#{id}_generator", :id => "#{id}_generator", :generate => ctl}))
143
- Core::build_node2(builder, Nodes.writer2({:name => "PARAMS CSV Writer", :id => "#{id}_csv_writer", :fileURL => "#{id}_counter.prm", :outputFieldNames => "false", :quotedStrings => "false"}))
144
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{id}_csv_writer:0", :fromNode => "#{id}_generator:0", :metadata => "trash_metadata"}))
145
- end
146
-
147
- subgraph_reformat_func = <<HEREDOC
148
-
149
- function integer transform() {
150
- $out.0.all = "graphs/#{id}_loop.grf";
151
- return ALL;
152
- }
153
- HEREDOC
154
-
155
- fail_reformat = <<HEREDOC
156
- function integer transform() {
157
- raiseError("Loop failed");
158
- }
159
- HEREDOC
160
-
161
-
162
- builder.Phase(:number => phase += 1) do
163
- Core::build_node2(builder, Nodes.reformat2({:name => "#{id} Reformat graph", :id => "#{id}_reformat_graph", :transformation => subgraph_reformat_func}))
164
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{id}_reformat_graph:0", :fromNode => "#{id}_reformat:1", :metadata => "file_list"}))
165
- Core::build_node2(builder, Nodes.run_graph2({
166
- :guiName => id,
167
- :name => id,
168
- :id => "#{id}_run_graph"
169
- }))
170
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{id}_run_graph:0", :fromNode => "#{id}_reformat_graph:0", :metadata => "trash_metadata"}))
171
- Core::build_node2(builder, Nodes.reformat2({:name => "#{id} Reformat fail", :id => "#{id}_reformat_fail", :transformation => fail_reformat}))
172
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{id}_reformat_fail:0", :fromNode => "#{id}_run_graph:1", :metadata => "run_graph_failure_metadata"}))
173
- Core::build_node2(builder, Nodes.trash2({:name => "#{id}_trash", :id => "#{id}_trash", :debugPrint => true}))
174
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{id}_trash:0", :fromNode => "#{id}_reformat_fail:0", :metadata => "run_graph_failure_metadata"}))
175
- end
176
- end
177
-
178
-
179
- end
180
- end
181
- end
182
-
183
- def self.create_incremental_sf_downloading_graph(file, taps, options={})
184
- metadata = options[:metadata]
185
- store = options[:store] || "${GDC_EVENTSTORE}"
186
- s3_backup = options[:s3_backup]
187
-
188
- File.open(file, "w") do |file|
189
- builder = Builder::XmlMarkup.new(:target=>file, :indent=>2)
190
- builder.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
191
- builder.Graph({:name => "Goodsales incremental Downloader"}) do
192
- builder.Global do
193
- Helpers::property_file(builder, {:id => "params_params", :fileURL => "params.prm"})
194
- Helpers::property_file(builder, {:id => "workspace_params", :fileURL => "workspace.prm"})
195
-
196
- Helpers::create_lookup_meta(builder)
197
- taps.each do |tap|
198
- module_name = tap[:object]
199
- file = tap[:id] || module_name
200
-
201
- builder.Metadata({:id => "#{file}_s3_metadata"}) do |builder|
202
- Helpers::csv_metadata(builder, GoodData::Bam::Metadata.add_field(Metadata.get_target_metadata(Tap.prepare_for_s3_backup(tap)), {:name => "Timestamp"}))
203
- end
204
-
205
- tap = Tap.prepare_for_sf_downloader(tap)
206
- builder.Metadata({:id => "#{file}_source_metadata"}) do |builder|
207
- Helpers::csv_metadata(builder, Metadata.get_source_metadata(tap))
208
- end
209
-
210
- builder.Metadata({:id => "#{file}_es_metadata"}) do |builder|
211
- Helpers::csv_metadata(builder, Metadata.add_timestamp_as_date(Metadata.get_target_metadata(tap)))
212
- end
213
-
214
- Core::build_node2(builder, Nodes.lookup2({:name => "gdLookup0", :id => "gdLookup0", :type => Nodes::GD_LOOKUP, :metadata => "lookup_metadata"}))
215
-
216
- end
217
-
218
- Helpers::sf_connection(builder, {})
219
- Helpers::property(builder, {:id => "SFDC_CLIENT_ID", :value => "gooddata/gooddata/"})
220
- Helpers::property(builder, {:id => "SFDC_LOGIN_HOSTNAME", :value => options[:sf_server] || "login.salesforce.com"})
221
- Helpers::property(builder, {:id => "SFDC_NAME", :value => "Salesforce connection"})
222
- Helpers::property(builder, {:id => "SFDC_PASSWORD", :value => options[:sf_password]})
223
- Helpers::property(builder, {:id => "SFDC_TOKEN", :value => options[:sf_token]})
224
- Helpers::property(builder, {:id => "SFDC_USERNAME", :value => options[:sf_login]})
225
- Helpers::property_file(builder, {:id => "workspace_params", :fileURL => "workspace.prm"})
226
- end
227
-
228
- phase = 1
229
-
230
- taps.each do |tap|
231
- module_name = tap[:object]
232
- file = tap[:id]
233
- dataset = file || module_name
234
- source_file = tap[:source]
235
-
236
- has_timestamp = Tap.has_output_field?(tap, "Timestamp")
237
- timestamp_field = Tap.find_output_field(tap, "Timestamp")
238
- id_field = Tap.find_output_field(tap, "Id")
239
- tap = Tap.prepare_for_sf_downloader(tap)
240
- builder.Phase(:number => phase += 1) do
241
- Core::build_node2(builder, Nodes.es_truncate2({:guiName => dataset, :store => store, :entity => dataset, :timestamp => "${#{dataset}_TRUNCATE_DATE}", :name => "#{module_name} es truncate", :id => "#{module_name}_es_truncate"}))
242
- end
243
-
244
- builder.Phase(:number => phase += 1) do
245
- fields = tap[:fields]
246
- mapping = "{\"xmlFieldsMapping\":{\"xmlFields\":["
247
- add = fields.map do |f|
248
- "{\"xmlFieldMapping\":{\"name\":\"#{f[:name]}\",\"label\":\"#{f[:label]}\",\"xmlPath\":\"#{f[:name]}\",\"metadataField\":\"#{f[:name]}\"}}"
249
- end
250
- stuff = mapping + add.join(",") + "]}}"
251
-
252
- mandatory_fields = fields.reject {|f| f[:is_mandatory] == false }.map {|f| f[:name] + ";"}.join
253
-
254
- Core::build_node2(builder, Nodes.sfdc_reader2({:name => "#{file} SF Reader", :id => "#{file}_reader", :soql => Helpers::generate_incremental_select(tap), :sfdcConnection => "SFDC", :fieldsMapping => stuff, :mandatoryFields => mandatory_fields}))
255
-
256
-
257
- es_transformation_source = if has_timestamp
258
- "function integer transform() {\n$out.0.* = $in.0.*;\n$out.0.Id = $in.0.#{id_field[:name]};\n$out.0.Timestamp = str2date($in.0.#{timestamp_field[:name]},\"joda:yyyy-MM-dd'T'HH:mm:ss.SSSZZ\");;\nreturn OK;\n}"
259
- else
260
- "function integer transform() {\n$out.0.* = $in.0.*;\n$out.0.Id = $in.0.#{id_field[:name]};\n$out.0.Timestamp = long2date(${GRAPH_STARTED_TIMESTAMP});\nreturn OK;\n}"
261
- end
262
-
263
- Core::build_node2(builder, Nodes.copy2({:name => "#{file} copy", :id => "#{file}_copy"}))
264
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_copy:0", :fromNode => "#{file}_reader:0", :metadata => "#{file}_source_metadata"}))
265
- Core::build_node2(builder, Nodes.writer2({:enabled => "disabled", :name => "#{file} CSV Writer", :id => "#{file}_csv", :fileURL => "data/#{dataset.downcase}.csv", :outputFieldNames => "true"}))
266
-
267
- Core::build_node2(builder, Nodes.reformat2({:name => "#{file} Reformat", :id => "#{file}_es_reformat", :transformation => es_transformation_source}))
268
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_es_reformat:0", :fromNode => "#{file}_copy:1", :metadata => "#{file}_source_metadata"}))
269
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_csv:0", :fromNode => "#{file}_copy:0", :metadata => "#{file}_source_metadata"}))
270
-
271
- if s3_backup then
272
- if has_timestamp
273
-
274
- Core::build_node2(builder, Nodes.writer2({:enabled => "enabled", :name => "#{file} s3 Writer", :id => "#{file}_s3", :fileURL => "https://${S3_ACCESS_KEY_ID}:\`replace(\"${S3_SECRET_ACCESS_KEY}\",\"/\",\"%2F\")\`@${S3_BUCKETNAME}.s3.amazonaws.com/${GDC_PROJECT_ID}/#{file}/#{file}_\`date2long(today())\`", :outputFieldNames => true}))
275
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_s3:0", :fromNode => "#{file}_copy:2", :metadata => "#{file}_source_metadata"}))
276
-
277
- else
278
- Core::build_node2(builder, Nodes.reformat2({:name => "#{file} Reformat", :id => "#{file}_s3_reformat", :transformation => "function integer transform() {\n$out.0.* = $in.0.*;\n$out.0.Timestamp = toString(${GRAPH_STARTED_TIMESTAMP});\nreturn OK;\n}"}))
279
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_s3_reformat:0", :fromNode => "#{file}_copy:2", :metadata => "#{file}_source_metadata"}))
280
-
281
- Core::build_node2(builder, Nodes.writer2({:enabled => "enabled", :name => "#{file} s3 Writer", :id => "#{file}_s3", :fileURL => "https://${S3_ACCESS_KEY_ID}:\`replace(\"${S3_SECRET_ACCESS_KEY}\",\"/\",\"%2F\")\`@${S3_BUCKETNAME}.s3.amazonaws.com/${GDC_PROJECT_ID}/#{file}/#{file}_\`date2long(today())\`", :outputFieldNames => true}))
282
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_s3:0", :fromNode => "#{file}_s3_reformat:0", :metadata => "#{file}_s3_metadata"}))
283
-
284
- end
285
- end
286
-
287
-
288
- Core::build_node2(builder, Nodes.sort2({:sortKey => "Timestamp(a)",:name => "#{file} es Sort", :id => "#{file}_es_sort"}))
289
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_es_sort:0", :fromNode => "#{file}_es_reformat:0", :metadata => "#{file}_es_metadata"}))
290
-
291
- Core::build_node2(builder, Nodes.es_writer2({:name => "#{file} es Writer", :id => "#{file}_es", :store => store, :entityFieldsMapping => Helpers::create_es_write_json(Tap.add_timestamp_field(tap)).to_json}))
292
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_es:0", :fromNode => "#{file}_es_sort:0", :metadata => "#{file}_es_metadata"}))
293
-
294
- end
295
-
296
- builder.Phase(:number => phase += 1) do
297
- generate_func = <<HEREDOC
298
- function integer generate() {
299
- date time_end = jodaStr2date("${#{dataset}_END}",["yyyy-MM-dd'T'HH:mm:ss.SSSZZ"], 'en_US', 'UTC', 'UTC');
300
- $out.0.key = "#{dataset}_LAST_RUN";
301
- $out.0.value = jodaDate2str(time_end,"yyyy-MM-dd'T'HH:mm:ss.SSSZZ", 'en_US', 'UTC');
302
- return OK;
303
- }
304
- HEREDOC
305
-
306
- Core::build_node2(builder, Nodes.data_generator2({:guiName => dataset, :name => "generator_#{phase}", :id => "generator_#{phase}", :generate => generate_func}))
307
- Core::build_node2(builder, Nodes.lookup_reader_writer2({:guiName => dataset, :lookupTable => "gdLookup0", :id => "gd_lookup_reader_#{phase}" }))
308
- Core::build_node2(builder, Nodes.edge2({:toNode => "gd_lookup_reader_#{phase}:0", :fromNode => "generator_#{phase}:0", :metadata => "lookup_metadata"}))
309
-
310
- end
311
- end
312
- end
313
- end
314
- end
315
-
316
-
317
-
318
- def self.create_incremental_sf_history_init_graph(file, taps, options={})
319
- metadata = options[:metadata]
320
- store = options[:store] || "${GDC_EVENTSTORE}"
321
- s3_backup = options[:s3_backup]
322
-
323
-
324
- client = GoodData::Bam::Commands.get_sf_client(options)
325
-
326
- File.open(file, "w") do |file|
327
- builder = Builder::XmlMarkup.new(:target=>file, :indent=>2)
328
- builder.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
329
- builder.Graph({:name => "Goodsales incremental Downloader"}) do
330
- builder.Global do
331
- Helpers::property_file(builder, {:id => "params_params", :fileURL => "params.prm"})
332
- Helpers::property_file(builder, {:id => "workspace_params", :fileURL => "workspace.prm"})
333
-
334
- Helpers::create_lookup_meta(builder)
335
- builder.Metadata({:id => "data_metadata"}) do |builder|
336
- Helpers::csv_metadata(builder, {:name => "data_metadata",:fields => [{:name => "Id"}, {:name => "Timestamp"}, {:name => "Value"}]})
337
- end
338
-
339
- builder.Metadata({:id => "es_metadata"}) do |builder|
340
- Helpers::csv_metadata(builder, {:name => "data_metadata",:fields => [{:name => "Id"}, {:name => "Timestamp", :type => "date"}, {:name => "Value"}]})
341
- end
342
-
343
- Core::build_node2(builder, Nodes.lookup2({:name => "gdLookup0", :id => "gdLookup0", :type => Nodes::GD_LOOKUP, :metadata => "lookup_metadata"}))
344
-
345
- Helpers::sf_connection(builder, {})
346
- Helpers::property(builder, {:id => "SFDC_CLIENT_ID", :value => "gooddata/gooddata/"})
347
- Helpers::property(builder, {:id => "SFDC_LOGIN_HOSTNAME", :value => options[:sf_server] || "login.salesforce.com"})
348
- Helpers::property(builder, {:id => "SFDC_NAME", :value => "Salesforce connection"})
349
- Helpers::property(builder, {:id => "SFDC_PASSWORD", :value => options[:sf_password]})
350
- Helpers::property(builder, {:id => "SFDC_TOKEN", :value => options[:sf_token]})
351
- Helpers::property(builder, {:id => "SFDC_USERNAME", :value => options[:sf_login]})
352
- Helpers::property_file(builder, {:id => "workspace_params", :fileURL => "workspace.prm"})
353
- end
354
-
355
- phase = 1
356
-
357
- taps_with_history = []
358
- taps.each do |tap|
359
- module_name = tap[:object]
360
- dataset = tap[:id]
361
- source_file = tap[:source]
362
-
363
- has_timestamp = Tap.has_output_field?(tap, "Timestamp")
364
- timestamp_field = Tap.find_output_field(tap, "Timestamp")
365
- id_field = Tap.find_output_field(tap, "Id")
366
- tap = Tap.prepare_for_sf_downloader(tap)
367
- builder.Phase(:number => phase += 1) do
368
- # Core::build_node2(builder, Nodes.es_truncate2({:guiName => dataset, :store => store, :entity => dataset, :timestamp => "${#{dataset}_TRUNCATE_DATE}", :name => "#{module_name} es truncate", :id => "#{module_name}_es_truncate"}))
369
- end
370
-
371
- fields = tap[:fields]
372
-
373
- puts tap[:object]
374
- sf_object = tap[:object]
375
- id_field = Tap.find_output_field(tap, "Id")
376
- timestamp_field = Tap.find_output_field(tap, "Timestamp")
377
-
378
-
379
- objects_to_get = Helpers.objects_for_history(client, tap)
380
-
381
- (tap[:fields] - [id_field, timestamp_field]).each_with_index do |field, i|
382
- builder.Phase(:number => phase += 1) do
383
-
384
- f = field[:name]
385
-
386
- selects = objects_to_get.reduce([]) do |memo, o|
387
- fields = client.fields(o)
388
- generic_field_history = ["NewValue", "OldValue", "ParentId"].all? {|f| fields.include?(f)}
389
- specific_field_history = ["NewValue", "OldValue", "#{sf_object}Id"].all? {|f| fields.include?(f)}
390
- specific_history = ["SystemModstamp", "#{sf_object}Id"].all? {|f| fields.include?(f)}
391
-
392
- select, mapping, mandatory = if generic_field_history
393
- [
394
- "SELECT NewValue, CreatedDate, ParentId FROM #{o} WHERE Field = '#{f}'",
395
- "{\"xmlFieldsMapping\":{\"xmlFields\":[
396
- {\"xmlFieldMapping\":{\"name\":\"NewValue\",\"label\":\"NewValue\",\"xmlPath\":\"NewValue\",\"metadataField\":\"Value\"}},
397
- {\"xmlFieldMapping\":{\"name\":\"CreatedDate\",\"label\":\"CreatedDate\",\"xmlPath\":\"CreatedDate\",\"metadataField\":\"Timestamp\"}},
398
- {\"xmlFieldMapping\":{\"name\":\"ParentId\",\"label\":\"ParentId\",\"xmlPath\":\"ParentId\",\"metadataField\":\"Id\"}}
399
- ]}}",
400
- ["ParentId", "NewValue", "CreatedDate"]
401
- ]
402
- elsif specific_field_history
403
- [
404
-
405
- "SELECT NewValue, CreatedDate, #{sf_object}Id FROM #{o} WHERE Field = '#{f}'",
406
- "{\"xmlFieldsMapping\":{\"xmlFields\":[
407
- {\"xmlFieldMapping\":{\"name\":\"NewValue\",\"label\":\"NewValue\",\"xmlPath\":\"NewValue\",\"metadataField\":\"Value\"}},
408
- {\"xmlFieldMapping\":{\"name\":\"CreatedDate\",\"label\":\"CreatedDate\",\"xmlPath\":\"CreatedDate\",\"metadataField\":\"Timestamp\"}},
409
- {\"xmlFieldMapping\":{\"name\":\"#{sf_object}Id\",\"label\":\"#{sf_object}Id\",\"xmlPath\":\"#{sf_object}Id\",\"metadataField\":\"Id\"}}
410
- ]}}",
411
- ["#{sf_object}Id", "NewValue", "CreatedDate"]
412
- ]
413
- elsif specific_history
414
- if fields.include?(f)
415
- [
416
- "SELECT #{f}, SystemModstamp, #{sf_object}Id FROM #{o}",
417
- "{\"xmlFieldsMapping\":{\"xmlFields\":[
418
- {\"xmlFieldMapping\":{\"name\":\"#{f}\",\"label\":\"#{f}\",\"xmlPath\":\"#{f}\",\"metadataField\":\"Value\"}},
419
- {\"xmlFieldMapping\":{\"name\":\"SystemModstamp\",\"label\":\"SystemModstamp\",\"xmlPath\":\"SystemModstamp\",\"metadataField\":\"Timestamp\"}},
420
- {\"xmlFieldMapping\":{\"name\":\"#{sf_object}Id\",\"label\":\"#{o}Id\",\"xmlPath\":\"#{o}Id\",\"metadataField\":\"Id\"}}
421
- ]}}",
422
- ["#{sf_object}Id", f, "SystemModstamp"]
423
- ]
424
- else
425
- [nil, nil]
426
- end
427
- else
428
- fail "Unrecognized fields configuration for historization in SF."
429
- end
430
- if select.nil?
431
- memo
432
- else
433
- memo.concat([{
434
- :object => o,
435
- :query => select,
436
- <<<<<<< HEAD
437
- :mapping => mapping
438
- =======
439
- :mapping => mapping,
440
- :mandatory => mandatory
441
- >>>>>>> Added historical SF downloader
442
- }])
443
- end
444
- end
445
-
446
- unless selects.empty?
447
- taps_with_history.concat([tap])
448
- selects = selects.concat([{
449
- :object => sf_object,
450
- :query => "SELECT Id, #{f}, SystemModstamp FROM #{sf_object}",
451
- :mapping => "{\"xmlFieldsMapping\":{\"xmlFields\":[
452
- {\"xmlFieldMapping\":{\"name\":\"#{f}\",\"label\":\"#{f}\",\"xmlPath\":\"#{f}\",\"metadataField\":\"Value\"}},
453
- {\"xmlFieldMapping\":{\"name\":\"SystemModstamp\",\"label\":\"SystemModstamp\",\"xmlPath\":\"SystemModstamp\",\"metadataField\":\"Timestamp\"}},
454
- {\"xmlFieldMapping\":{\"name\":\"Id\",\"label\":\"Id\",\"xmlPath\":\"Id\",\"metadataField\":\"Id\"}}
455
- ]}}",
456
- :mandatory => ["Id", f, "SystemModstamp"]
457
- }])
458
- selects.each_with_index do |obj, i|
459
-
460
- o = obj[:object]
461
- mapping = obj[:mapping]
462
- select = obj[:query]
463
- mandatory = obj[:mandatory]
464
-
465
- Core::build_node2(builder, Nodes.sfdc_reader2({:name => "#{o} SF Reader #{i}", :id => "#{f}_#{o}_reader", :soql => select, :sfdcConnection => "SFDC", :fieldsMapping => mapping, :mandatoryFields => mandatory.join(';')}))
466
- puts "#{f}_#{o}_reader:0 -> #{f}_#{sf_object}_gather:#{i}"
467
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{f}_#{sf_object}_gather:#{i}", :fromNode => "#{f}_#{o}_reader:0", :metadata => "data_metadata"}))
468
- end
469
- Core::build_node2(builder, Nodes.gather2({:name => "#{f} Gather", :id => "#{f}_#{sf_object}_gather"}))
470
- Core::build_node2(builder, Nodes.sort2({:sortKey => "Timestamp(a)",:name => "#{f}_#{sf_object}_sort", :id => "#{f}_#{sf_object}_sort"}))
471
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{f}_#{sf_object}_sort:0", :fromNode => "#{f}_#{sf_object}_gather:0", :metadata => "data_metadata"}))
472
-
473
- Core::build_node2(builder, Nodes.copy2({:name => "#{file} copy", :id => "#{f}_#{sf_object}_copy"}))
474
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{f}_#{sf_object}_copy:0", :fromNode => "#{f}_#{sf_object}_sort:0", :metadata => "data_metadata"}))
475
-
476
- if s3_backup
477
- Core::build_node2(builder, Nodes.writer2({:enabled => "enabled", :name => "#{f}_#{sf_object} s3 Writer", :id => "#{f}_#{sf_object}_s3", :fileURL => "https://${S3_ACCESS_KEY_ID}:\`replace(\"${S3_SECRET_ACCESS_KEY}\",\"/\",\"%2F\")\`@${S3_BUCKETNAME}.s3.amazonaws.com/${GDC_PROJECT_ID}/#{sf_object}/#{f}_#{sf_object}_\`date2long(today())\`", :outputFieldNames => true}))
478
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{f}_#{sf_object}_s3:0", :fromNode => "#{f}_#{sf_object}_copy:1", :metadata => "data_metadata"}))
479
- end
480
-
481
- transform = "function integer transform() {\n$out.0.* = $in.0.*;\n$out.0.Timestamp = str2date($in.0.Timestamp,\"joda:yyyy-MM-dd'T'HH:mm:ss.SSSZZ\");\nreturn OK;\n}"
482
-
483
- Core::build_node2(builder, Nodes.reformat2({:name => "Reformat", :id => "#{f}_#{sf_object}_reformat", :transformation => transform}))
484
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{f}_#{sf_object}_reformat:0", :fromNode => "#{f}_#{sf_object}_copy:0", :metadata => "data_metadata"}))
485
-
486
- Core::build_node2(builder, Nodes.es_writer2({:name => "#{file} es Writer", :id => "#{f}_#{sf_object}_es", :store => store, :entityFieldsMapping => Helpers::create_es_write_json({:type => :tap, :id => tap[:id], :fields => [{:name => "Id"}, {:name => "Timestamp"}, {:name => f, :meta => "Value"}]}).to_json}))
487
-
488
- # Core::build_node2(builder, Nodes.trash2({:name => "#{f}_#{sf_object}_es", :id => "#{f}_#{sf_object}_es", :debugPrint => true}))
489
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{f}_#{sf_object}_es:0", :fromNode => "#{f}_#{sf_object}_reformat:0", :metadata => "es_metadata"}))
490
- end
491
- end
492
- end
493
- end
494
- taps_with_history.each do |tap|
495
- puts "#{tap[:id]}_LAST_RUN"
496
- builder.Phase(:number => phase += 1) do
497
- generate_func = <<HEREDOC
498
- function integer generate() {
499
- date time_end = jodaStr2date("${#{tap[:id]}_END}",["yyyy-MM-dd'T'HH:mm:ss.SSSZZ"], 'en_US', 'UTC', 'UTC');
500
- $out.0.key = "#{tap[:id]}_LAST_RUN";
501
- $out.0.value = jodaDate2str(time_end,"yyyy-MM-dd'T'HH:mm:ss.SSSZZ", 'en_US', 'UTC');
502
- return OK;
503
- }
504
- HEREDOC
505
-
506
- Core::build_node2(builder, Nodes.data_generator2({:guiName => tap[:id], :name => "generator_#{phase}", :id => "generator_#{phase}", :generate => generate_func}))
507
- Core::build_node2(builder, Nodes.lookup_reader_writer2({:guiName => tap[:id], :lookupTable => "gdLookup0", :id => "gd_lookup_reader_#{phase}" }))
508
- Core::build_node2(builder, Nodes.edge2({:toNode => "gd_lookup_reader_#{phase}:0", :fromNode => "generator_#{phase}:0", :metadata => "lookup_metadata"}))
509
-
510
- end
511
- end
512
- end
513
- end
514
- end
515
-
516
- def self.generate_downloaders(home, project, params)
517
- home = Pathname(home)
518
-
519
- incremental_taps = Taps.get_incremental(project[:taps])
520
-
521
- sf_taps = Taps.get_salesforce(incremental_taps)
522
- file_taps = Taps.get_file(incremental_taps)
523
-
524
- create_incremental_downloader_run_graph(home + "main.grf", incremental_taps)
525
- # create_incremental_sf_downloading_graph(home + "incremental.grf", sf_taps, params)
526
- create_incremental_sf_history_init_graph(home + "incremental.grf", sf_taps, params)
527
-
528
- file_taps.each do |tap|
529
- id = tap[:id]
530
- Helpers::loop_over_file(home + "#{tap[:id]}_loop.grf", {
531
- :token => id,
532
- :file_to_loop => "data/#{id}_files_to_read.csv",
533
- :graph_to_run => "graphs/#{id}_download.grf"
534
- })
535
- create_incremental_file_downloading_graph(home + "#{tap[:id]}_download.grf", [tap], params)
536
-
537
- end
538
- end
539
-
540
-
541
- def self.generate_history_downloaders(home, project, params)
542
- home = Pathname(home)
543
-
544
- incremental_taps = Taps.get_incremental(project[:taps])
545
-
546
- sf_taps = Taps.get_salesforce(incremental_taps)
547
- file_taps = Taps.get_file(incremental_taps)
548
-
549
- create_incremental_downloader_run_graph(home + "main.grf", incremental_taps)
550
- create_incremental_sf_history_init_graph(home + "incremental.grf", sf_taps, params)
551
- end
552
-
553
- def self.create_incremental_file_downloading_graph(file, taps, options={})
554
- metadata = options[:metadata]
555
- store = options[:store] || "${GDC_EVENTSTORE}"
556
- s3_backup = options[:s3_backup]
557
- File.open(file, "w") do |file|
558
- builder = Builder::XmlMarkup.new(:target=>file, :indent=>2)
559
- builder.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
560
- builder.Graph({:name => "Goodsales incremental Downloader"}) do
561
- builder.Global do
562
- Helpers::property_file(builder, {:id => "workspace_params", :fileURL => "workspace.prm"})
563
- Helpers::create_lookup_meta(builder)
564
- taps.each do |tap|
565
- module_name = tap[:object]
566
- file = tap[:id] || module_name
567
-
568
- Helpers::property_file(builder, {:id => "params_params", :fileURL => "#{file}_item.prm"})
569
-
570
- builder.Metadata({:id => "#{file}_s3_metadata"}) do |builder|
571
- Helpers::csv_metadata(builder, GoodData::Bam::Metadata.add_field(Metadata.get_target_metadata(Tap.prepare_for_s3_backup(tap)), {:name => "Timestamp"}))
572
- end
573
-
574
- tap = Tap.prepare_for_sf_downloader(tap)
575
- builder.Metadata({:id => "#{file}_source_metadata"}) do |builder|
576
- Helpers::csv_metadata(builder, Metadata.get_source_metadata(tap))
577
- end
578
-
579
- builder.Metadata({:id => "#{file}_es_metadata"}) do |builder|
580
- Helpers::csv_metadata(builder, GoodData::Bam::Metadata.add_timestamp_as_date(Metadata.get_target_metadata(tap)))
581
- end
582
- Core::build_node2(builder, Nodes.lookup2({:name => "gdLookup0", :id => "gdLookup0", :type => Nodes::GD_LOOKUP, :metadata => "lookup_metadata"}))
583
- end
584
- end
585
-
586
- phase = 1
587
-
588
- taps.each do |tap|
589
- module_name = tap[:object]
590
- file = tap[:id]
591
- dataset = file || module_name
592
- source_file = tap[:source]
593
-
594
-
595
- has_timestamp = GoodData::Bam::Tap.has_output_field?(tap, "Timestamp")
596
- timestamp_field = GoodData::Bam::Tap.find_output_field(tap, "Timestamp")
597
- id_field = GoodData::Bam::Tap.find_output_field(tap, "Id")
598
-
599
- tap = Tap.prepare_for_sf_downloader(tap)
600
-
601
- builder.Phase(:number => phase += 1) do
602
- fields = tap[:fields]
603
- mapping = "{\"xmlFieldsMapping\":{\"xmlFields\":["
604
- add = fields.map do |f|
605
- "{\"xmlFieldMapping\":{\"name\":\"#{f[:name]}\",\"label\":\"#{f[:label]}\",\"xmlPath\":\"#{f[:name]}\",\"metadataField\":\"#{f[:name]}\"}}"
606
- end
607
- stuff = mapping + add.join(",") + "]}}"
608
-
609
- mandatory_fields = fields.reject {|f| f[:is_mandatory] == false }.map {|f| f[:name] + ";"}.join
610
-
611
- Core::build_node2(builder, Nodes.reader2({:name => "#{file} File Reader", :id => "#{file}_reader", :fileURL => "${FILE}"}))
612
- es_transformation_source = if has_timestamp
613
- "function integer transform() {\n$out.0.* = $in.0.*;\n$out.0.Id = $in.0.#{id_field[:name]};\n$out.0.Timestamp = str2date($in.0.#{timestamp_field[:name]},\"joda:yyyy-MM-dd'T'HH:mm:ss.SSSZZ\");;\nreturn OK;\n}"
614
- else
615
- "function integer transform() {\n$out.0.* = $in.0.*;\n$out.0.Id = $in.0.#{id_field[:name]};\n$out.0.Timestamp = long2date(${GRAPH_STARTED_TIMESTAMP});\nreturn OK;\n}"
616
- end
617
-
618
- # build_node2(builder, Nodes.reformat2({:name => "#{file} Reformat", :id => "#{file}_reformat", :transformation => transformation_source}))
619
-
620
- Core::build_node2(builder, Nodes.copy2({:name => "#{file} copy", :id => "#{file}_copy"}))
621
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_copy:0", :fromNode => "#{file}_reader:0", :metadata => "#{file}_source_metadata"}))
622
- Core::build_node2(builder, Nodes.writer2({:enabled => "disabled", :name => "#{file} CSV Writer", :id => "#{file}_csv", :fileURL => "data/#{dataset.downcase}.csv", :outputFieldNames => "true"}))
623
-
624
- Core::build_node2(builder, Nodes.reformat2({:name => "#{file} Reformat", :id => "#{file}_es_reformat", :transformation => es_transformation_source}))
625
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_es_reformat:0", :fromNode => "#{file}_copy:1", :metadata => "#{file}_source_metadata"}))
626
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_csv:0", :fromNode => "#{file}_copy:0", :metadata => "#{file}_source_metadata"}))
627
-
628
- if s3_backup
629
- if has_timestamp
630
- Core::build_node2(builder, Nodes.writer2({:enabled => "enabled", :name => "#{file} s3 Writer", :id => "#{file}_s3", :fileURL => "https://${S3_ACCESS_KEY_ID}:\`replace(\"${S3_SECRET_ACCESS_KEY}\",\"/\",\"%2F\")\`@${S3_BUCKETNAME}.s3.amazonaws.com/${GDC_PROJECT_ID}/#{file}/#{file}_\`date2long(today())\`", :outputFieldNames => true}))
631
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_s3:0", :fromNode => "#{file}_copy:2", :metadata => "#{file}_source_metadata"}))
632
- else
633
- Core::build_node2(builder, Nodes.reformat2({:name => "#{file} Reformat", :id => "#{file}_s3_reformat", :transformation => "function integer transform() {\n$out.0.* = $in.0.*;\n$out.0.Timestamp = toString(${GRAPH_STARTED_TIMESTAMP});\nreturn OK;\n}"}))
634
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_s3_reformat:0", :fromNode => "#{file}_copy:2", :metadata => "#{file}_source_metadata"}))
635
-
636
- Core::build_node2(builder, Nodes.writer2({:enabled => "enabled", :name => "#{file} s3 Writer", :id => "#{file}_s3", :fileURL => "https://${S3_ACCESS_KEY_ID}:\`replace(\"${S3_SECRET_ACCESS_KEY}\",\"/\",\"%2F\")\`@${S3_BUCKETNAME}.s3.amazonaws.com/${GDC_PROJECT_ID}/#{file}/#{file}_\`date2long(today())\`", :outputFieldNames => true}))
637
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_s3:0", :fromNode => "#{file}_s3_reformat:0", :metadata => "#{file}_s3_metadata"}))
638
- end
639
- # Core::build_node2(builder, Nodes.writer2({:enabled => "enabled", :name => "#{file} s3 Writer", :id => "#{file}_s3", :fileURL => "https://${S3_ACCESS_KEY_ID}:\`replace(\"${S3_SECRET_ACCESS_KEY}\",\"/\",\"%2F\")\`@${S3_BUCKETNAME}.s3.amazonaws.com/${GDC_PROJECT_ID}/#{file}/#{file}_\`date2long(today())\`", :outputFieldNames => true}))
640
- # Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_s3:0", :fromNode => "#{file}_copy:2", :metadata => "#{file}_source_metadata"}))
641
- end
642
-
643
-
644
- Core::build_node2(builder, Nodes.sort2({:sortKey => "Timestamp(a)",:name => "#{file} es Sort", :id => "#{file}_es_sort"}))
645
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_es_sort:0", :fromNode => "#{file}_es_reformat:0", :metadata => "#{file}_es_metadata"}))
646
- Core::build_node2(builder, Nodes.es_writer2({:name => "#{file} es Writer", :id => "#{file}_es", :store => store, :entityFieldsMapping => Helpers::create_es_write_json(Tap.add_timestamp_field(tap)).to_json}))
647
- Core::build_node2(builder, Nodes.edge2({:toNode => "#{file}_es:0", :fromNode => "#{file}_es_sort:0", :metadata => "#{file}_es_metadata"}))
648
- end
649
-
650
- builder.Phase(:number => phase += 1) do
651
- Core::build_node2(builder, Nodes.file_delete2({:guiName => "#{file}_file_delete", :name => "#{file}_file_delete", :id => "#{file}_file_delete", :baseURL => "${FILE}"}))
652
- end
653
-
654
- end
655
-
656
- end
657
- end
658
- end
659
-
660
- end
661
- end
662
- end
663
- end