gd_bam 0.0.15 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +313 -5
- data/bin/bam +126 -48
- data/lib/bam/version.rb +1 -1
- data/lib/bam.rb +51 -0
- data/lib/base/errors.rb +15 -0
- data/lib/base/flow.rb +37 -0
- data/lib/base/graph.rb +23 -0
- data/lib/base/metadata.rb +107 -0
- data/lib/base/project.rb +95 -0
- data/lib/base/repo.rb +35 -0
- data/lib/base/sink.rb +44 -0
- data/lib/base/step.rb +47 -0
- data/lib/base/tap.rb +167 -0
- data/lib/base/taps.rb +19 -0
- data/lib/cloud_connect/dsl/cc.rb +42 -0
- data/lib/cloud_connect/dsl/es_helpers.rb +49 -0
- data/lib/cloud_connect/dsl/helpers.rb +199 -0
- data/lib/{nodes → cloud_connect/dsl}/nodes.rb +106 -16
- data/lib/cloud_connect/dsl/sf_helpers.rb +39 -0
- data/lib/cloud_connect/dsl/structure_helpers.rb +94 -0
- data/lib/commands/commands.rb +110 -0
- data/lib/commands/deployment.rb +217 -0
- data/lib/commands/docs_commands.rb +41 -0
- data/lib/commands/gd_commands.rb +95 -0
- data/lib/commands/scaffold_commands.rb +103 -0
- data/lib/commands/sf_commands.rb +37 -0
- data/lib/commands/validators.rb +19 -0
- data/lib/compatibility.rb +19 -0
- data/lib/compiler/compiler.rb +76 -0
- data/lib/compiler/etl_visitor.rb +165 -0
- data/lib/dsl/dsl.rb +125 -0
- data/lib/generators/downloaders.rb +449 -0
- data/lib/generators/etl.rb +261 -0
- data/lib/generators/validators.rb +445 -0
- data/lib/graphs/docentize.grf +1 -1
- data/lib/graphs/dummy.grf +1 -1
- data/lib/graphs/goodsales_v2/docentize.grf +47 -0
- data/lib/graphs/goodsales_v2/dummy.grf +46 -0
- data/lib/graphs/goodsales_v2/load_history.grf +579 -0
- data/lib/graphs/goodsales_v2/process_account.grf +47 -0
- data/lib/graphs/goodsales_v2/process_activity.grf +222 -0
- data/lib/graphs/goodsales_v2/process_activity_dim.grf +88 -0
- data/lib/graphs/goodsales_v2/process_activity_owner.grf +48 -0
- data/lib/graphs/goodsales_v2/process_forecast.grf +20 -0
- data/lib/graphs/goodsales_v2/process_opp_records.grf +84 -0
- data/lib/graphs/goodsales_v2/process_opportunity.grf +46 -0
- data/lib/graphs/goodsales_v2/process_opportunity_line_item.grf +171 -0
- data/lib/graphs/goodsales_v2/process_opportunity_snapshot.grf +94 -0
- data/lib/graphs/goodsales_v2/process_owner.grf +48 -0
- data/lib/graphs/goodsales_v2/process_stage.grf +51 -0
- data/lib/graphs/goodsales_v2/process_stage_history.grf +184 -0
- data/lib/graphs/goodsales_v2/process_velocity_duration.grf +140 -0
- data/lib/graphs/process_account.grf +1 -1
- data/lib/graphs/process_activity.grf +1 -1
- data/lib/graphs/process_activity_dim.grf +1 -1
- data/lib/graphs/process_activity_owner.grf +1 -1
- data/lib/graphs/process_forecast.grf +1 -1
- data/lib/graphs/process_opp_records.grf +1 -1
- data/lib/graphs/process_opportunity.grf +1 -1
- data/lib/graphs/process_opportunity_line_item.grf +1 -1
- data/lib/graphs/process_opportunity_snapshot.grf +1 -1
- data/lib/graphs/process_owner.grf +1 -1
- data/lib/graphs/process_stage.grf +1 -1
- data/lib/graphs/process_stage_history.grf +1 -1
- data/lib/graphs/process_velocity_duration.grf +1 -1
- data/lib/nodes/clover_gen.rb +59 -946
- data/lib/nodes/dependency.rb +95 -96
- data/lib/runtime.rb +7 -648
- data/lib/utils/utils.rb +66 -0
- data/templates/flow.rb.erb +7 -6
- data/templates/join_template.grf.erb +1 -1
- data/templates/reformat_template.grf.erb +1 -1
- data/templates/sink.json.erb +28 -0
- data/templates/tap.json.erb +3 -5
- data/templates/workspace.prm.erb +4 -0
- metadata +50 -8
- data/lib/contract_checkers/contract_checkers.rb +0 -53
- data/lib/dsl/project_dsl.rb +0 -259
- data/lib/repo/1_config.json +0 -8
- data/templates/dataset.json.erb +0 -13
- data/templates/source.json.erb +0 -22
@@ -0,0 +1,42 @@
|
|
1
|
+
module GoodData
|
2
|
+
module CloudConnect
|
3
|
+
module Core
|
4
|
+
|
5
|
+
include GoodData::CloudConnect
|
6
|
+
|
7
|
+
def self.build_node2(builder, node)
|
8
|
+
if node[:type] == Nodes::EDGE
|
9
|
+
builder.tag!("Edge", node)
|
10
|
+
elsif node[:type] == Nodes::SF_CONNECTION
|
11
|
+
builder.tag!("Connection", node)
|
12
|
+
elsif node[:type] == Nodes::FILE_LIST
|
13
|
+
builder.tag!("Node", node.remove(:output_mapping)) do |xml|
|
14
|
+
xml.attr({:name => "outputMapping"}) do |attr|
|
15
|
+
transformation = node[:output_mapping]
|
16
|
+
attr.cdata! transformation
|
17
|
+
end
|
18
|
+
end
|
19
|
+
elsif node[:type] == Nodes::REFORMAT || node[:type] == Nodes::EXT_HASH_JOIN
|
20
|
+
builder.tag!("Node", node.remove(:transformation)) do |xml|
|
21
|
+
xml.attr({:name => "transform"}) do |attr|
|
22
|
+
transformation = node[:transformation]
|
23
|
+
attr.cdata! transformation
|
24
|
+
end
|
25
|
+
end
|
26
|
+
elsif node[:type] == Nodes::DATA_GENERATOR
|
27
|
+
builder.tag!("Node", node.remove(:transformation)) do |xml|
|
28
|
+
xml.attr({:name => "generate"}) do |attr|
|
29
|
+
transformation = node[:generate]
|
30
|
+
attr.cdata! transformation
|
31
|
+
end
|
32
|
+
end
|
33
|
+
elsif node[:type] == Nodes::PERSISTENT_LOOKUP || node[:type] == Nodes::GD_LOOKUP
|
34
|
+
builder.tag!("LookupTable", node)
|
35
|
+
else
|
36
|
+
builder.tag!("Node", node)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module GoodData
|
2
|
+
module CloudConnect
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
def self.create_es_write_json(tap)
|
6
|
+
fail "Only tap should be used here. You provided \"#{tap}\"" unless tap[:type] == :tap
|
7
|
+
{
|
8
|
+
:entityName => tap[:id] || tap[:object],
|
9
|
+
:fieldsMapping => tap[:fields].reduce({}) do |memo, f|
|
10
|
+
|
11
|
+
if f.has_key?(:acts_as)
|
12
|
+
|
13
|
+
f[:acts_as].each do |a|
|
14
|
+
type = case a
|
15
|
+
when "Id"
|
16
|
+
"recordid"
|
17
|
+
when "Timestamp"
|
18
|
+
"timestamp"
|
19
|
+
else
|
20
|
+
f[:type] || "attribute"
|
21
|
+
end
|
22
|
+
memo[a] = {
|
23
|
+
:name => a,
|
24
|
+
:type => type
|
25
|
+
}
|
26
|
+
end
|
27
|
+
else
|
28
|
+
type = case f[:name]
|
29
|
+
when "Id"
|
30
|
+
"recordid"
|
31
|
+
when "Timestamp"
|
32
|
+
"timestamp"
|
33
|
+
else
|
34
|
+
f[:type] || "attribute"
|
35
|
+
end
|
36
|
+
|
37
|
+
memo[f[:name]] = {
|
38
|
+
:name => f[:name],
|
39
|
+
:type => type
|
40
|
+
}
|
41
|
+
end
|
42
|
+
memo
|
43
|
+
end
|
44
|
+
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
module GoodData
|
2
|
+
module CloudConnect
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
def self.property(builder, data)
|
6
|
+
builder.Property({
|
7
|
+
:id => data[:id],
|
8
|
+
:name => data[:name] || data[:id],
|
9
|
+
:value => data[:value]
|
10
|
+
})
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.property_file(builder, data)
|
14
|
+
builder.Property({
|
15
|
+
:id => data[:id],
|
16
|
+
:fileURL => data[:fileURL]
|
17
|
+
})
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.create_trash_meta(builder)
|
21
|
+
builder.Metadata({:id => "trash_metadata"}) do |builder|
|
22
|
+
csv_metadata(builder, {
|
23
|
+
:name => "trash_metadata",
|
24
|
+
:fields => [{:type => "string", :name => "all"}]
|
25
|
+
})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.save_metadata(filename, data)
|
30
|
+
dirname = File.dirname(filename)
|
31
|
+
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
|
32
|
+
|
33
|
+
File.open(filename, "w") do |file|
|
34
|
+
builder = Builder::XmlMarkup.new(:target => file, :indent=>2)
|
35
|
+
builder.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
36
|
+
csv_metadata(builder, data)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.create_moving_graph(file, options={})
|
41
|
+
source = options[:source]
|
42
|
+
target = options[:target]
|
43
|
+
operation = options[:operation]
|
44
|
+
force = options[:force] || false
|
45
|
+
|
46
|
+
File.open(file, "w") do |file|
|
47
|
+
builder = Builder::XmlMarkup.new(:target=>file, :indent=>2)
|
48
|
+
builder.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
49
|
+
builder.Graph({
|
50
|
+
:name => "File Copy"
|
51
|
+
}) do
|
52
|
+
builder.Global do
|
53
|
+
builder.Metadata({:id => "list_metadata"}) do |builder|
|
54
|
+
Helpers::csv_metadata(builder, {
|
55
|
+
:name => "list_metadata",
|
56
|
+
:fields => [{:name=>"filePath", :type=>"string"}]
|
57
|
+
})
|
58
|
+
end
|
59
|
+
Helpers::property_file(builder, {:id => "workspace_params", :fileURL => "workspace.prm"})
|
60
|
+
end
|
61
|
+
builder.Phase(:number => 0) do
|
62
|
+
|
63
|
+
transformation_source = "function integer transform() {\n" + ([["filePath", "filePath"]].map {|t| "$out.0.#{t.last} = $in.0.#{t.first};"}.join("\n")) + "\nreturn OK;\n}"
|
64
|
+
Core::build_node2(builder, Nodes.file_list2(:baseURL => target, :id => "file_list", :output_mapping => transformation_source))
|
65
|
+
|
66
|
+
Core::build_node2(builder, Nodes.file_delete2(:baseURL => "${filePath}", :id => "file_delete"))
|
67
|
+
Core::build_node2(builder, Nodes.edge2({:toNode => "file_delete:0", :fromNode => "file_list:0", :metadata => "list_metadata"}))
|
68
|
+
end
|
69
|
+
builder.Phase(:number => 1) do
|
70
|
+
Core::build_node2(builder, Nodes.file_copy2({:sourcePath => source, :targetPath => target, :operation => operation, :id => "file_copy"}))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.csv_metadata(builder, description)
|
77
|
+
sf_description = description.merge({
|
78
|
+
:fieldDelimiter => ",",
|
79
|
+
:recordDelimiter => "\\n",
|
80
|
+
:type => "delimited",
|
81
|
+
})
|
82
|
+
metadata(builder, sf_description)
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.metadata(builder, description)
|
86
|
+
builder.Record({
|
87
|
+
:fieldDelimiter => description[:fieldDelimiter],
|
88
|
+
:name => description[:name],
|
89
|
+
:recordDelimiter => description[:recordDelimiter],
|
90
|
+
:type => description[:type]
|
91
|
+
}) do |record|
|
92
|
+
description[:fields].each do |field|
|
93
|
+
builder.Field :name => field[:name], :type => field[:type] || "string", :nullable => "true"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.create_lookup_meta(builder)
|
99
|
+
builder.Metadata({:id => "lookup_metadata"}) do |builder|
|
100
|
+
csv_metadata(builder, {
|
101
|
+
:name => "lookup_metadata",
|
102
|
+
:fields => [{:type => "string", :name => "key"}, {:type => "string", :name => "value"}]
|
103
|
+
})
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.create_file_list_meta(builder)
|
108
|
+
builder.Metadata({:id => "file_list"}) do |builder|
|
109
|
+
csv_metadata(builder, {
|
110
|
+
:name => "file_list",
|
111
|
+
:fields => [
|
112
|
+
{:name => "filePath", :type => "string"},
|
113
|
+
{:name => "fileName", :type => "string"}
|
114
|
+
]
|
115
|
+
})
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.create_read_error_meta(builder)
|
120
|
+
builder.Metadata({:id => "reader_error_metadata"}) do |builder|
|
121
|
+
csv_metadata(builder, {
|
122
|
+
:name => "reader_error_metadata",
|
123
|
+
:fields => [
|
124
|
+
{:name => "line_number", :type => "integer"},
|
125
|
+
{:name => "field_number", :type => "integer"},
|
126
|
+
{:name => "record", :type => "string"},
|
127
|
+
{:name => "message", :type => "string"},
|
128
|
+
{:name => "file", :type => "string"}
|
129
|
+
]
|
130
|
+
})
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.create_run_graph_failure_metadata(builder)
|
135
|
+
builder.Metadata({:id => "run_graph_failure_metadata"}) do |builder|
|
136
|
+
csv_metadata(builder, {
|
137
|
+
:name => "run_graph_failure_metadata",
|
138
|
+
:fields => [
|
139
|
+
{:type => "string", :name => "graph"},
|
140
|
+
{:type => "string", :name => "result"},
|
141
|
+
{:type => "string", :name => "description"},
|
142
|
+
{:type => "string", :name => "message"},
|
143
|
+
{:type => "decimal", :name => "duration"}
|
144
|
+
]
|
145
|
+
})
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.create_run_graph(file, options={})
|
150
|
+
subgraphs = options[:subgraphs]
|
151
|
+
flow = options[:flow]
|
152
|
+
File.open(file, "w") do |file|
|
153
|
+
builder = Builder::XmlMarkup.new(:target=>file, :indent=>2)
|
154
|
+
builder.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
155
|
+
builder.Graph({
|
156
|
+
:name => "Run graph"
|
157
|
+
}) do
|
158
|
+
builder.Global do
|
159
|
+
property_file(builder, {:id => "workspace_params", :fileURL => "workspace.prm"})
|
160
|
+
property_file(builder, {:id => "params_params", :fileURL => "params.prm"})
|
161
|
+
create_trash_meta(builder)
|
162
|
+
create_lookup_meta(builder)
|
163
|
+
|
164
|
+
end
|
165
|
+
phase = 0
|
166
|
+
subgraphs.each do |subgraph|
|
167
|
+
name = GoodData::Bam::Step.step_name(GoodData::Bam::Graph.create(:path => subgraph))
|
168
|
+
# Pathname(subgraph).basename.to_s.chomp(Pathname(subgraph).extname)
|
169
|
+
builder.Phase(:number => phase+1) do
|
170
|
+
id1 = GoodData::CloudConnect::Nodes.get_id
|
171
|
+
id2 = GoodData::CloudConnect::Nodes.get_id
|
172
|
+
ctl = "function integer generate() {$out.0.all = \"FLOW=#{flow}\";return OK;}"
|
173
|
+
Core::build_node2(builder, Nodes.data_generator2({:name => id1, :id => id1, :generate => ctl}))
|
174
|
+
Core::build_node2(builder, Nodes.edge2({:toNode => "#{id2}:0", :fromNode => "#{id1}:0", :metadata => "trash_metadata"}))
|
175
|
+
Core::build_node2(builder, Nodes.writer2({:name => "PARAMS CSV Writer", :id => "#{id2}", :fileURL => "params.prm", :outputFieldNames => "false", :quotedStrings => "false"}))
|
176
|
+
end
|
177
|
+
builder.Phase(:number => phase+2) do
|
178
|
+
|
179
|
+
id1 = GoodData::CloudConnect::Nodes.get_id
|
180
|
+
id2 = GoodData::CloudConnect::Nodes.get_id
|
181
|
+
ctl = "function integer generate() {$out.0.all = \"NAME=#{name}\";return OK;}"
|
182
|
+
Core::build_node2(builder, Nodes.data_generator2({:name => id1, :id => id1, :generate => ctl}))
|
183
|
+
Core::build_node2(builder, Nodes.edge2({:toNode => "#{id2}:0", :fromNode => "#{id1}:0", :metadata => "trash_metadata"}))
|
184
|
+
Core::build_node2(builder, Nodes.writer2({:name => "PARAMS CSV Writer", :id => "#{id2}", :fileURL => "params.prm", :outputFieldNames => "false", :append => "true", :quotedStrings => "false"}))
|
185
|
+
end
|
186
|
+
|
187
|
+
builder.Phase(:number => phase+3) do
|
188
|
+
Core::build_node2(builder, Nodes.run_graph2({:guiName => name, :name => name, :id => flow, :graphName => subgraph}))
|
189
|
+
end
|
190
|
+
phase += 4
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -1,16 +1,21 @@
|
|
1
1
|
module GoodData
|
2
|
-
module
|
2
|
+
module CloudConnect
|
3
3
|
module Nodes
|
4
4
|
|
5
5
|
SF_CONNECTION = "SFDC"
|
6
6
|
EDGE = "EDGE"
|
7
7
|
WRITER = "DATA_WRITER"
|
8
|
+
DEDUP = "DEDUP"
|
8
9
|
READER = "DATA_READER"
|
9
10
|
SF_READER = "SF_READER"
|
10
11
|
REFORMAT = "REFORMAT"
|
12
|
+
FILE_BACKUP = "FILE_BACKUP"
|
11
13
|
PERSISTENT_LOOKUP = "persistentLookup"
|
12
14
|
GD_LOOKUP = "gdLookup"
|
13
15
|
GD_ESTORE_WRITER = "GD_ESTORE_WRITER"
|
16
|
+
GD_FILE_BACKUP = "FILE_BACKUP"
|
17
|
+
GD_FILE_COPY = "FILE_COPY_MOVE"
|
18
|
+
FILE_DELETE = "FILE_DELETE"
|
14
19
|
GD_ESTORE_READER = "GD_ESTORE_READER"
|
15
20
|
ENABLED = "ENABLED"
|
16
21
|
DEFAULT_HEIGHT = "77"
|
@@ -25,12 +30,17 @@ module GoodData
|
|
25
30
|
TRASH = "TRASH"
|
26
31
|
LOOKUP_TABLE_READER_WRITER = "LOOKUP_TABLE_READER_WRITER"
|
27
32
|
FILE_COPY_MOVE = "FILE_COPY_MOVE"
|
28
|
-
FILE_DELETE = "FILE_DELETE"
|
29
33
|
FILE_LIST = "FILE_LIST"
|
30
34
|
EXT_SORT = "EXT_SORT"
|
31
35
|
EXT_HASH_JOIN = "EXT_HASH_JOIN"
|
32
36
|
NORMALIZER = "NORMALIZER"
|
33
|
-
|
37
|
+
|
38
|
+
MAP_ALL = <<HEREDOC
|
39
|
+
function integer transform() {
|
40
|
+
$out.0.* = $in.0.*;
|
41
|
+
return ALL;
|
42
|
+
}
|
43
|
+
HEREDOC
|
34
44
|
|
35
45
|
DEFAULT_NODE_PARAMS = {
|
36
46
|
:enabled => ENABLED,
|
@@ -38,6 +48,11 @@ module GoodData
|
|
38
48
|
:guiWidth => DEFAULT_WIDTH
|
39
49
|
}
|
40
50
|
|
51
|
+
$__cloud_connect_id = 0
|
52
|
+
def self.get_id()
|
53
|
+
$__cloud_connect_id += 1
|
54
|
+
end
|
55
|
+
|
41
56
|
def self.node(data, options={})
|
42
57
|
defaults = options[:defaults] || {}
|
43
58
|
required = options[:required] || []
|
@@ -45,7 +60,7 @@ module GoodData
|
|
45
60
|
output_data = defaults.merge(data)
|
46
61
|
required.each do |key|
|
47
62
|
unless output_data.has_key?(key)
|
48
|
-
fail "#{key} is required but not provided"
|
63
|
+
fail "#{key} is required but not provided. You defined \"#{data}\""
|
49
64
|
end
|
50
65
|
end
|
51
66
|
output_data
|
@@ -55,7 +70,9 @@ module GoodData
|
|
55
70
|
defaults = DEFAULT_NODE_PARAMS.merge(options[:defaults] || {})
|
56
71
|
required = (options[:required] || []).concat([:type, :id])
|
57
72
|
allowed = options[:allowed] || []
|
58
|
-
output_data = defaults.merge(
|
73
|
+
output_data = defaults.merge({
|
74
|
+
:id => get_id()
|
75
|
+
}).merge(data)
|
59
76
|
|
60
77
|
node(output_data, {
|
61
78
|
:allowed => [:enabled, :guiName, :id, :type, :guiHeight, :guiWidth, :name].concat(allowed),
|
@@ -113,6 +130,67 @@ module GoodData
|
|
113
130
|
})
|
114
131
|
end
|
115
132
|
|
133
|
+
|
134
|
+
|
135
|
+
def self.file_delete2(data, options={})
|
136
|
+
local_defaults = {
|
137
|
+
:type => FILE_DELETE
|
138
|
+
}
|
139
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
140
|
+
|
141
|
+
base_node(defaults.merge(data), {
|
142
|
+
:allowed => [:baseURL],
|
143
|
+
:defaults => defaults,
|
144
|
+
:required => [:baseURL]
|
145
|
+
})
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.backup2(data, options={})
|
149
|
+
local_defaults = {
|
150
|
+
:type => GD_FILE_BACKUP,
|
151
|
+
:mode => "ALL_TO_ONE",
|
152
|
+
:appendTimestamp => true,
|
153
|
+
:makeDirs => true
|
154
|
+
}
|
155
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
156
|
+
|
157
|
+
base_node(defaults.merge(data), {
|
158
|
+
:allowed => [:sourcePath, :makeDirs, :appendTimestamp, :mode, :baseURL],
|
159
|
+
:defaults => defaults,
|
160
|
+
:required => []
|
161
|
+
})
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.file_backup2(data, options={})
|
165
|
+
local_defaults = {
|
166
|
+
:type => FILE_BACKUP,
|
167
|
+
:makeDirs => true
|
168
|
+
}
|
169
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
170
|
+
|
171
|
+
base_node(defaults.merge(data), {
|
172
|
+
:allowed => [:sourcePath, :baseURL, :mode, :makeDirs],
|
173
|
+
:defaults => defaults,
|
174
|
+
:required => []
|
175
|
+
})
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.file_copy2(data, options={})
|
179
|
+
local_defaults = {
|
180
|
+
:type => GD_FILE_COPY,
|
181
|
+
:operation => "COPY",
|
182
|
+
:makeDirs => true
|
183
|
+
}
|
184
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
185
|
+
|
186
|
+
base_node(defaults.merge(data), {
|
187
|
+
:allowed => [:sourcePath, :targetPath, :makeDirs, :operation, :baseURL],
|
188
|
+
:defaults => defaults,
|
189
|
+
:required => []
|
190
|
+
})
|
191
|
+
end
|
192
|
+
|
193
|
+
|
116
194
|
def self.sfdc_reader2(data, options={})
|
117
195
|
local_defaults = {
|
118
196
|
:type => SF_READER,
|
@@ -127,6 +205,20 @@ module GoodData
|
|
127
205
|
|
128
206
|
end
|
129
207
|
|
208
|
+
def self.dedup2(data, options={})
|
209
|
+
local_defaults = {
|
210
|
+
:type => DEDUP,
|
211
|
+
}
|
212
|
+
defaults = local_defaults.merge(options[:defaults] || {})
|
213
|
+
|
214
|
+
base_node(defaults.merge(data), {
|
215
|
+
:allowed => [],
|
216
|
+
:defaults => defaults,
|
217
|
+
:required => [:dedupKey]
|
218
|
+
})
|
219
|
+
|
220
|
+
end
|
221
|
+
|
130
222
|
def self.run_graph2(data, options={})
|
131
223
|
local_defaults = {
|
132
224
|
:type => RUN_GRAPH,
|
@@ -136,8 +228,7 @@ module GoodData
|
|
136
228
|
|
137
229
|
base_node(defaults.merge(data), {
|
138
230
|
:allowed => [:paramsToPass, :type, :name, :clientId, :loginHostname, :name, :username, :password, :passwordEncrypted, :token, :id],
|
139
|
-
:defaults => defaults
|
140
|
-
:required => [:graphName]
|
231
|
+
:defaults => defaults
|
141
232
|
})
|
142
233
|
end
|
143
234
|
|
@@ -247,7 +338,7 @@ module GoodData
|
|
247
338
|
base_node(defaults.merge(data), {
|
248
339
|
:allowed => [],
|
249
340
|
:defaults => defaults,
|
250
|
-
:required => []
|
341
|
+
:required => [:output_mapping]
|
251
342
|
})
|
252
343
|
end
|
253
344
|
|
@@ -312,10 +403,11 @@ module GoodData
|
|
312
403
|
})
|
313
404
|
end
|
314
405
|
|
315
|
-
|
316
|
-
def self.file_delete2(data, options={})
|
406
|
+
def self.file_copy2(data, options={})
|
317
407
|
local_defaults = {
|
318
|
-
:type =>
|
408
|
+
:type => FILE_COPY_MOVE,
|
409
|
+
:operation => "COPY",
|
410
|
+
:baseURL => "${PROJECT}"
|
319
411
|
}
|
320
412
|
defaults = local_defaults.merge(options[:defaults] || {})
|
321
413
|
base_node(defaults.merge(data), {
|
@@ -325,11 +417,9 @@ module GoodData
|
|
325
417
|
})
|
326
418
|
end
|
327
419
|
|
328
|
-
def self.
|
420
|
+
def self.gather2(data, options={})
|
329
421
|
local_defaults = {
|
330
|
-
:type =>
|
331
|
-
:operation => "COPY",
|
332
|
-
:baseURL => "${PROJECT}"
|
422
|
+
:type => SIMPLE_GATHER,
|
333
423
|
}
|
334
424
|
defaults = local_defaults.merge(options[:defaults] || {})
|
335
425
|
base_node(defaults.merge(data), {
|
@@ -338,7 +428,7 @@ module GoodData
|
|
338
428
|
:required => []
|
339
429
|
})
|
340
430
|
end
|
341
|
-
|
431
|
+
|
342
432
|
|
343
433
|
def self.copy2(data, options={})
|
344
434
|
local_defaults = {
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module GoodData
|
2
|
+
module CloudConnect
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
def self.generate_select(tap)
|
6
|
+
fields = tap[:fields].map do |f|
|
7
|
+
f.has_key?(:multi_currency) ? "convertCurrency(#{f[:name]})" : f[:name]
|
8
|
+
end
|
9
|
+
condition = tap[:condition].nil?() ? "" : "WHERE #{tap[:condition]}"
|
10
|
+
limit = tap[:limit].nil?() ? "" : "LIMIT #{tap[:limit]}"
|
11
|
+
"SELECT #{fields.join(', ')} FROM #{tap[:object]} #{condition} #{limit}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.generate_incremental_select(tap)
|
15
|
+
if tap[:condition].blank?
|
16
|
+
tap[:condition] = "SystemModstamp > ${#{tap[:id]}_START} AND SystemModstamp <= ${#{tap[:id]}_END}"
|
17
|
+
else
|
18
|
+
tap[:condition] += " AND SystemModstamp > ${#{tap[:id]}_START} AND SystemModstamp <= ${#{tap[:id]}_END}"
|
19
|
+
end
|
20
|
+
generate_select(tap)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.sf_connection(builder, data)
|
24
|
+
builder.Connection({
|
25
|
+
:clientId => "${SFDC_CLIENT_ID}",
|
26
|
+
:id => "SFDC",
|
27
|
+
:loginHostname => "${SFDC_LOGIN_HOSTNAME}",
|
28
|
+
:name => "${SFDC_NAME}",
|
29
|
+
:password => "${SFDC_PASSWORD}",
|
30
|
+
:passwordEncrypted => "true",
|
31
|
+
:token => "${SFDC_TOKEN}",
|
32
|
+
:type => "SFDC",
|
33
|
+
:username => "${SFDC_USERNAME}",
|
34
|
+
:passwordEncrypted => "false"
|
35
|
+
})
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module GoodData
|
2
|
+
module CloudConnect
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
include GoodData::CloudConnect
|
6
|
+
|
7
|
+
def self.loop_over_file(file, options={})
|
8
|
+
file_to_loop = options[:file_to_loop]
|
9
|
+
token = options[:token]
|
10
|
+
graph_to_run = options[:graph_to_run]
|
11
|
+
|
12
|
+
fail "token not defined" if token.blank?
|
13
|
+
fail "file to loop if not defined" if file_to_loop.blank?
|
14
|
+
fail "graph_to_run not defined" if graph_to_run.blank?
|
15
|
+
|
16
|
+
|
17
|
+
File.open(file, "w") do |f|
|
18
|
+
|
19
|
+
builder = Builder::XmlMarkup.new(:target=>f, :indent=>2)
|
20
|
+
builder.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
21
|
+
builder.Graph({
|
22
|
+
:name => "Contract Checker: File list reader"
|
23
|
+
}) do
|
24
|
+
builder.Global do
|
25
|
+
Helpers::property_file(builder, {:id => "workspace_params", :fileURL => "workspace.prm"})
|
26
|
+
Helpers::property_file(builder, {:id => "skiplines_params", :fileURL => "#{token}_counter.prm"})
|
27
|
+
|
28
|
+
Helpers::create_trash_meta(builder)
|
29
|
+
Helpers::create_run_graph_failure_metadata(builder)
|
30
|
+
Helpers::create_file_list_meta(builder)
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
reformat_func = <<HEREDOC
|
35
|
+
function integer transform() {
|
36
|
+
$out.0.all = "FILE=" + $in.0.filePath;
|
37
|
+
return ALL;
|
38
|
+
}
|
39
|
+
HEREDOC
|
40
|
+
|
41
|
+
builder.Phase(:number => 0) do
|
42
|
+
Core::build_node2(builder, Nodes.reader2({
|
43
|
+
:id => "#{token}_reader",
|
44
|
+
:guiName => "#{token}_reader",
|
45
|
+
:name => "#{token}_reader",
|
46
|
+
:dataPolicy => "Strict",
|
47
|
+
:skipRows => "${#{token}_SKIP_LINES}",
|
48
|
+
:numRecords => 1,
|
49
|
+
:fileURL => file_to_loop
|
50
|
+
}))
|
51
|
+
Core::build_node2(builder, Nodes.reformat2({:name => "#{token} Reformat", :id => "#{token}_reformat", :transformation => reformat_func }))
|
52
|
+
Core::build_node2(builder, Nodes.edge2({:toNode => "#{token}_reformat:0", :fromNode => "#{token}_reader:0", :metadata => "file_list" }))
|
53
|
+
Core::build_node2(builder, Nodes.writer2({:name => "PARAMS CSV Writer", :id => "#{token}_writer", :fileURL => "#{token}_item.prm" , :outputFieldNames => "false", :quotedStrings => "false"}))
|
54
|
+
Core::build_node2(builder, Nodes.edge2({:toNode => "#{token}_writer:0", :fromNode => "#{token}_reformat:0", :metadata => "trash_metadata" }))
|
55
|
+
end
|
56
|
+
builder.Phase(:number => 1) do
|
57
|
+
|
58
|
+
reformat_func = <<HEREDOC
|
59
|
+
function integer transform() {
|
60
|
+
$out.0.all = "#{graph_to_run}";
|
61
|
+
return ALL;
|
62
|
+
}
|
63
|
+
HEREDOC
|
64
|
+
|
65
|
+
fail_func = <<HEREDOC
|
66
|
+
function integer transform() {
|
67
|
+
raiseError("Graph #{graph_to_run} failed");
|
68
|
+
}
|
69
|
+
HEREDOC
|
70
|
+
Core::build_node2(builder, Nodes.reformat2({:name => "#{token} Reformat_graph", :id => "#{token}_reformat_graph", :transformation => reformat_func }))
|
71
|
+
Core::build_node2(builder, Nodes.edge2({:toNode => "#{token}_reformat_graph:0", :fromNode => "#{token}_reformat:1", :metadata => "trash_metadata" }))
|
72
|
+
Core::build_node2(builder, Nodes.run_graph2({:guiName => "#{token}_validate", :name => "#{token}_validate", :id => "#{token}_validate" }))
|
73
|
+
Core::build_node2(builder, Nodes.edge2({:toNode => "#{token}_validate:0", :fromNode => "#{token}_reformat_graph:0", :metadata => "trash_metadata" }))
|
74
|
+
Core::build_node2(builder, Nodes.reformat2({:name => "#{token} Reformat_fail", :id => "#{token}_reformat_fail", :transformation => fail_func }))
|
75
|
+
Core::build_node2(builder, Nodes.edge2({:toNode => "#{token}_reformat_fail:0", :fromNode => "#{token}_validate:1", :metadata => "run_graph_failure_metadata" }))
|
76
|
+
Core::build_node2(builder, Nodes.trash2({:name => "#{token}_trash", :id => "#{token}_trash", :debugPrint => true}))
|
77
|
+
Core::build_node2(builder, Nodes.edge2({:toNode => "#{token}_trash:0", :fromNode => "#{token}_reformat_fail:0", :metadata => "run_graph_failure_metadata"}))
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
builder.Phase(:number => 2) do
|
82
|
+
|
83
|
+
|
84
|
+
ctl = "function integer generate() {$out.0.all = \"#{token}_SKIP_LINES=\" + toString(${#{token}_SKIP_LINES} + 1);return OK;}"
|
85
|
+
Core::build_node2(builder, Nodes.data_generator2({:name => "#{token}_generator", :id => "#{token}_generator", :generate => ctl}))
|
86
|
+
Core::build_node2(builder, Nodes.writer2({:name => "PARAMS CSV Writer", :id => "#{token}_csv_writer", :fileURL => "#{token}_counter.prm", :outputFieldNames => "false", :quotedStrings => "false"}))
|
87
|
+
Core::build_node2(builder, Nodes.edge2({:toNode => "#{token}_csv_writer:0", :fromNode => "#{token}_generator:0", :metadata => "trash_metadata" }))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|