gooddata 0.5.16 → 0.6.0.pre2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +2 -0
- data/bin/gooddata +291 -8
- data/gooddata.gemspec +14 -5
- data/lib/gooddata/client.rb +34 -5
- data/lib/gooddata/commands/api.rb +27 -30
- data/lib/gooddata/commands/process.rb +137 -0
- data/lib/gooddata/commands/profile.rb +5 -5
- data/lib/gooddata/commands/projects.rb +107 -40
- data/lib/gooddata/commands/runners.rb +37 -0
- data/lib/gooddata/commands/scaffold.rb +30 -0
- data/lib/gooddata/connection.rb +31 -19
- data/lib/gooddata/extract.rb +1 -1
- data/lib/gooddata/goodzilla/goodzilla.rb +40 -0
- data/lib/gooddata/model.rb +418 -138
- data/lib/gooddata/models/attribute.rb +24 -0
- data/lib/gooddata/models/dashboard.rb +60 -0
- data/lib/gooddata/models/data_result.rb +4 -6
- data/lib/gooddata/models/data_set.rb +20 -0
- data/lib/gooddata/models/display_form.rb +7 -0
- data/lib/gooddata/models/fact.rb +17 -0
- data/lib/gooddata/models/metadata.rb +69 -17
- data/lib/gooddata/models/metric.rb +90 -0
- data/lib/gooddata/models/process.rb +112 -0
- data/lib/gooddata/models/profile.rb +1 -1
- data/lib/gooddata/models/project.rb +85 -29
- data/lib/gooddata/models/report.rb +45 -0
- data/lib/gooddata/models/report_definition.rb +139 -0
- data/lib/gooddata/version.rb +1 -1
- data/lib/templates/bricks/brick.rb.erb +7 -0
- data/lib/templates/bricks/main.rb.erb +4 -0
- data/spec/goodzilla_spec.rb +57 -0
- data/spec/model_dsl_spec.rb +22 -0
- data/test/test_commands.rb +1 -1
- data/test/test_model.rb +6 -6
- metadata +137 -16
- data/bin/igd.rb +0 -33
- data/lib/gooddata/command.rb +0 -75
- data/lib/gooddata/commands/help.rb +0 -104
- data/lib/gooddata/commands/version.rb +0 -7
- data/test/helper.rb +0 -13
data/lib/gooddata/extract.rb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
module GoodData::SmallGoodZilla
|
2
|
+
|
3
|
+
def self.get_facts(a_maql_string)
|
4
|
+
a_maql_string.scan(/#\"([^\"]+)\"/).flatten
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.get_attributes(a_maql_string)
|
8
|
+
a_maql_string.scan(/@\"([^\"]+)\"/).flatten
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.get_metrics(a_maql_string)
|
12
|
+
a_maql_string.scan(/\?"([^\"]+)\"/).flatten
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.interpolate(values, dictionaries)
|
16
|
+
{
|
17
|
+
:facts => interpolate_values(values[:facts], dictionaries[:facts]),
|
18
|
+
:attributes => interpolate_values(values[:attributes], dictionaries[:attributes]),
|
19
|
+
:metrics => interpolate_values(values[:metrics], dictionaries[:metrics])
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.interpolate_values(keys, values)
|
24
|
+
x = values.values_at(*keys)
|
25
|
+
keys.zip(x)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.interpolate_metric(metric, dictionary)
|
29
|
+
interpolated = interpolate({
|
30
|
+
:facts => GoodData::SmallGoodZilla.get_facts(metric),
|
31
|
+
:attributes => GoodData::SmallGoodZilla.get_attributes(metric),
|
32
|
+
:metrics => GoodData::SmallGoodZilla.get_metrics(metric)
|
33
|
+
}, dictionary)
|
34
|
+
metric = interpolated[:facts].reduce(metric) {|memo, item| memo.sub("#\"#{item[0]}\"", "[#{item[1]}]")}
|
35
|
+
metric = interpolated[:attributes].reduce(metric) {|memo, item| memo.sub("@\"#{item[0]}\"", "[#{item[1]}]")}
|
36
|
+
metric = interpolated[:metrics].reduce(metric) {|memo, item| memo.sub("?\"#{item[0]}\"", "[#{item[1]}]")}
|
37
|
+
metric
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/lib/gooddata/model.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'open-uri'
|
2
2
|
|
3
3
|
##
|
4
4
|
# Module containing classes that counter-part GoodData server-side meta-data
|
@@ -32,30 +32,303 @@ module GoodData
|
|
32
32
|
|
33
33
|
SKIP_FIELD = false
|
34
34
|
|
35
|
-
BEGINNING_OF_TIMES = Date.parse('1/1/1900')
|
36
|
-
|
37
35
|
class << self
|
38
|
-
def add_dataset(
|
39
|
-
|
36
|
+
def add_dataset(name, columns, project = nil)
|
37
|
+
Schema.new('columns' => columns, 'name' => name)
|
38
|
+
add_schema(schema , project)
|
40
39
|
end
|
41
40
|
|
42
41
|
def add_schema(schema, project = nil)
|
43
|
-
unless schema.
|
42
|
+
unless schema.respond_to?(:to_maql_create) || schema.is_a?(String) then
|
44
43
|
raise ArgumentError.new("Schema object or schema file path expected, got '#{schema}'")
|
45
44
|
end
|
46
|
-
schema = Schema.load
|
45
|
+
schema = Schema.load(schema) unless schema.respond_to?(:to_maql_create)
|
47
46
|
project = GoodData.project unless project
|
48
47
|
ldm_links = GoodData.get project.md[LDM_CTG]
|
49
48
|
ldm_uri = Links.new(ldm_links)[LDM_MANAGE_CTG]
|
50
49
|
GoodData.post ldm_uri, { 'manage' => { 'maql' => schema.to_maql_create } }
|
51
50
|
end
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
end
|
53
|
+
|
54
|
+
class ProjectBuilder
|
55
|
+
|
56
|
+
attr_reader :title, :datasets, :reports, :metrics, :uploads, :users, :assert_report, :date_dimensions
|
57
|
+
|
58
|
+
class << self
|
59
|
+
|
60
|
+
def create(title, options={}, &block)
|
61
|
+
pb = ProjectBuilder.new(title)
|
62
|
+
block.call(pb)
|
63
|
+
pb
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
def initialize(title)
|
69
|
+
@title = title
|
70
|
+
@datasets = []
|
71
|
+
@reports = []
|
72
|
+
@assert_tests = []
|
73
|
+
@metrics = []
|
74
|
+
@uploads = []
|
75
|
+
@users = []
|
76
|
+
@dashboards = []
|
77
|
+
@date_dimensions = []
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_date_dimension(name, options={})
|
81
|
+
@date_dimensions << {:urn => options[:urn], :name => name, :title => options[:title]}
|
82
|
+
end
|
83
|
+
|
84
|
+
def add_dataset(name, &block)
|
85
|
+
builder = GoodData::Model::SchemaBuilder.new(name)
|
86
|
+
block.call(builder)
|
87
|
+
@datasets << builder.to_hash
|
88
|
+
end
|
89
|
+
|
90
|
+
def add_report(title, options={})
|
91
|
+
@reports << {:title => title}.merge(options)
|
92
|
+
end
|
93
|
+
|
94
|
+
def add_metric(title, options={})
|
95
|
+
@metrics << {:title => title}.merge(options)
|
96
|
+
end
|
97
|
+
|
98
|
+
def add_dashboard(title, &block)
|
99
|
+
db = DashboardBuilder.new(title)
|
100
|
+
block.call(db)
|
101
|
+
@dashboards << db.to_hash
|
102
|
+
end
|
103
|
+
|
104
|
+
def load_metrics(file)
|
105
|
+
new_metrics = JSON.parse(open(file).read, :symbolize_names => true)
|
106
|
+
@metrics = @metrics + new_metrics
|
56
107
|
end
|
108
|
+
|
109
|
+
def load_datasets(file)
|
110
|
+
new_metrics = JSON.parse(open(file).read, :symbolize_names => true)
|
111
|
+
@datasets = @datasets + new_metrics
|
112
|
+
end
|
113
|
+
|
114
|
+
def assert_report(report, result)
|
115
|
+
@assert_tests << {:report => report, :result => result}
|
116
|
+
end
|
117
|
+
|
118
|
+
def upload(data, options={})
|
119
|
+
mode = options[:mode] || "FULL"
|
120
|
+
dataset = options[:dataset]
|
121
|
+
@uploads << {
|
122
|
+
:source => data,
|
123
|
+
:mode => mode,
|
124
|
+
:dataset => dataset
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
def add_users(users)
|
129
|
+
@users << users
|
130
|
+
end
|
131
|
+
|
132
|
+
def to_json
|
133
|
+
JSON.pretty_generate(to_hash)
|
134
|
+
end
|
135
|
+
|
136
|
+
def to_hash
|
137
|
+
{
|
138
|
+
:title => @title,
|
139
|
+
:datasets => @datasets,
|
140
|
+
:uploads => @uploads,
|
141
|
+
:dashboards => @dashboards,
|
142
|
+
:metrics => @metrics,
|
143
|
+
:reports => @reports,
|
144
|
+
:users => @users,
|
145
|
+
:assert_tests => @assert_tests,
|
146
|
+
:date_dimensions => @date_dimensions
|
147
|
+
}
|
148
|
+
end
|
149
|
+
|
57
150
|
end
|
58
151
|
|
152
|
+
class DashboardBuilder
|
153
|
+
|
154
|
+
def initialize(title)
|
155
|
+
@title = title
|
156
|
+
@tabs = []
|
157
|
+
end
|
158
|
+
|
159
|
+
def add_tab(tab, &block)
|
160
|
+
tb = TabBuilder.new(tab)
|
161
|
+
block.call(tb)
|
162
|
+
@tabs << tb
|
163
|
+
tb
|
164
|
+
end
|
165
|
+
|
166
|
+
def to_hash
|
167
|
+
{
|
168
|
+
:name => @name,
|
169
|
+
:tabs => @tabs.map{|tab| tab.to_hash}
|
170
|
+
}
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
class TabBuilder
|
175
|
+
|
176
|
+
def initialize(title)
|
177
|
+
@title = title
|
178
|
+
@stuff = []
|
179
|
+
end
|
180
|
+
|
181
|
+
def add_report(options={})
|
182
|
+
@stuff << {:type => :report}.merge(options)
|
183
|
+
end
|
184
|
+
|
185
|
+
def to_hash
|
186
|
+
{
|
187
|
+
:title => @title,
|
188
|
+
:items => @stuff
|
189
|
+
}
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
class SchemaBuilder
|
195
|
+
|
196
|
+
attr_accessor :title, :name
|
197
|
+
|
198
|
+
def initialize(name=nil)
|
199
|
+
@name = name
|
200
|
+
@columns = []
|
201
|
+
end
|
202
|
+
|
203
|
+
def add_column(column_def)
|
204
|
+
@columns.push(column_def)
|
205
|
+
self
|
206
|
+
end
|
207
|
+
|
208
|
+
def add_anchor(name, options={})
|
209
|
+
add_column({ :type => :anchor, :name => name}.merge(options))
|
210
|
+
self
|
211
|
+
end
|
212
|
+
|
213
|
+
def add_attribute(name, options={})
|
214
|
+
add_column({ :type => :attribute, :name => name}.merge(options))
|
215
|
+
self
|
216
|
+
end
|
217
|
+
|
218
|
+
def add_fact(name, options={})
|
219
|
+
add_column({ :type => :fact, :name => name}.merge(options))
|
220
|
+
self
|
221
|
+
end
|
222
|
+
|
223
|
+
def add_label(name, options={})
|
224
|
+
add_column({ :type => :label, :name => name}.merge(options))
|
225
|
+
self
|
226
|
+
end
|
227
|
+
|
228
|
+
def add_date(name, options={})
|
229
|
+
add_column({ :type => :date, :name => name}.merge(options))
|
230
|
+
end
|
231
|
+
|
232
|
+
def add_reference(name, options={})
|
233
|
+
add_column({ :type => :reference, :name => name}.merge(options))
|
234
|
+
end
|
235
|
+
|
236
|
+
def to_schema
|
237
|
+
Schema.new(to_hash)
|
238
|
+
end
|
239
|
+
|
240
|
+
def to_json
|
241
|
+
JSON.pretty_generate(to_hash)
|
242
|
+
end
|
243
|
+
|
244
|
+
def to_hash
|
245
|
+
h = {
|
246
|
+
:name => @name,
|
247
|
+
:columns => @columns
|
248
|
+
}
|
249
|
+
h.has_key?(:title) ? h.merge({:title => h[:title]}) : h
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
class ProjectCreator
|
254
|
+
|
255
|
+
class << self
|
256
|
+
def migrate(options={})
|
257
|
+
|
258
|
+
spec = options[:spec] || fail("You need to provide spec for migration")
|
259
|
+
spec = spec.to_hash
|
260
|
+
project = options[:project]
|
261
|
+
token = options[:token] || fail("You need to specify token for project creation")
|
262
|
+
new_project = GoodData::Project.create(:title => spec[:title], :auth_token => token)
|
263
|
+
|
264
|
+
begin
|
265
|
+
GoodData.with_project(new_project) do |p|
|
266
|
+
migrate_date_dimensions(p, spec[:date_dimensions])
|
267
|
+
migrate_datasets(p, spec[:datasets])
|
268
|
+
load(p, spec)
|
269
|
+
migrate_metrics(p, spec[:metrics])
|
270
|
+
migrate_reports(p, spec[:reports])
|
271
|
+
migrate_dashboards(p, spec[:dashboards])
|
272
|
+
migrate_users(p, spec[:users])
|
273
|
+
execute_tests(p, spec[:assert_tests])
|
274
|
+
p
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def migrate_date_dimensions(project, spec)
|
280
|
+
spec.each do |dd|
|
281
|
+
Model.add_schema(DateDimension.new(dd), project)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def migrate_datasets(project, spec)
|
286
|
+
spec.each do |ds|
|
287
|
+
project.add_dataset(GoodData::Model::Schema.new(ds))
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def migrate_reports(project, spec)
|
292
|
+
spec.each do |report|
|
293
|
+
project.add_report(report)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def migrate_dashboards(project, spec)
|
298
|
+
spec.each do |dash|
|
299
|
+
project.add_dashboard(dash)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def migrate_metrics(project, spec)
|
304
|
+
spec.each do |metric|
|
305
|
+
project.add_metric(metric)
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def migrate_users(project, spec)
|
310
|
+
spec.each do |user|
|
311
|
+
puts "Would migrate user #{user}"
|
312
|
+
# project.add_user(user)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def load(project, spec)
|
317
|
+
spec[:uploads].each do |load|
|
318
|
+
schema = GoodData::Model::Schema.new(spec[:datasets].detect {|d| d[:name] == load[:dataset]})
|
319
|
+
project.upload(load[:source], schema, load[:mode])
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def execute_tests(project, spec)
|
324
|
+
spec.each do |assert|
|
325
|
+
result = GoodData::ReportDefinition.execute(assert[:report])
|
326
|
+
fail "Test did not pass. Got #{result.table.inspect}, expected #{assert[:result].inspect}" if result.table != assert[:result]
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
59
332
|
class MdObject
|
60
333
|
attr_accessor :name, :title
|
61
334
|
|
@@ -72,7 +345,7 @@ module GoodData
|
|
72
345
|
# non-Latin character and then dropping non-alphanumerical characters.
|
73
346
|
#
|
74
347
|
def identifier
|
75
|
-
@identifier ||= "#{self.type_prefix}.#{
|
348
|
+
@identifier ||= "#{self.type_prefix}.#{name}"
|
76
349
|
end
|
77
350
|
end
|
78
351
|
|
@@ -82,13 +355,14 @@ module GoodData
|
|
82
355
|
# model abstractions.
|
83
356
|
#
|
84
357
|
class Schema < MdObject
|
85
|
-
attr_reader :fields, :attributes, :facts, :folders, :references, :labels
|
358
|
+
attr_reader :fields, :attributes, :facts, :folders, :references, :labels, :name, :title
|
86
359
|
|
87
360
|
def self.load(file)
|
88
361
|
Schema.new JSON.load(open(file))
|
89
362
|
end
|
90
363
|
|
91
|
-
def initialize(config,
|
364
|
+
def initialize(config, name = nil)
|
365
|
+
super()
|
92
366
|
@fields = []
|
93
367
|
@attributes = {}
|
94
368
|
@facts = {}
|
@@ -99,64 +373,45 @@ module GoodData
|
|
99
373
|
@references = {}
|
100
374
|
@labels = []
|
101
375
|
|
102
|
-
config[
|
103
|
-
|
104
|
-
|
376
|
+
config[:name] = name unless config[:name]
|
377
|
+
config[:title] = config[:title] || config[:name].humanize
|
378
|
+
fail 'Schema name not specified' unless config[:name]
|
379
|
+
self.name = config[:name]
|
380
|
+
self.title = config[:title]
|
105
381
|
self.config = config
|
106
382
|
end
|
107
383
|
|
108
|
-
def transform_header(headers)
|
109
|
-
result = fields.reduce([]) do |memo, f|
|
110
|
-
val = f.to_csv_header(headers)
|
111
|
-
memo << val unless val === SKIP_FIELD
|
112
|
-
memo
|
113
|
-
end
|
114
|
-
result.flatten
|
115
|
-
end
|
116
|
-
|
117
|
-
def transform_row(headers, row)
|
118
|
-
result = fields.reduce([]) do |memo, f|
|
119
|
-
val = f.to_csv_data(headers, row)
|
120
|
-
memo << val unless val === SKIP_FIELD
|
121
|
-
memo
|
122
|
-
end
|
123
|
-
result.flatten
|
124
|
-
end
|
125
|
-
|
126
384
|
def config=(config)
|
127
|
-
config[
|
128
|
-
case c[
|
129
|
-
when
|
385
|
+
config[:columns].each do |c|
|
386
|
+
case c[:type].to_s
|
387
|
+
when "attribute"
|
130
388
|
add_attribute c
|
131
|
-
when
|
389
|
+
when "fact"
|
132
390
|
add_fact c
|
133
|
-
when
|
391
|
+
when "date"
|
134
392
|
add_date c
|
135
|
-
when
|
393
|
+
when "anchor"
|
136
394
|
set_connection_point c
|
137
|
-
when
|
395
|
+
when "label"
|
138
396
|
add_label c
|
139
|
-
when
|
397
|
+
when "reference"
|
140
398
|
add_reference c
|
141
399
|
else
|
142
|
-
fail "Unexpected type #{c[
|
400
|
+
fail "Unexpected type #{c[:type]} in #{c.inspect}"
|
143
401
|
end
|
144
402
|
end
|
145
403
|
@connection_point = RecordsOf.new(nil, self) unless @connection_point
|
146
404
|
end
|
147
405
|
|
148
|
-
def
|
149
|
-
|
150
|
-
@title = title
|
406
|
+
def type_prefix
|
407
|
+
'dataset'
|
151
408
|
end
|
152
409
|
|
153
|
-
def type_prefix ; 'dataset' ; end
|
154
|
-
|
155
410
|
##
|
156
411
|
# Underlying fact table name
|
157
412
|
#
|
158
413
|
def table
|
159
|
-
@table ||= FACT_COLUMN_PREFIX +
|
414
|
+
@table ||= FACT_COLUMN_PREFIX + name
|
160
415
|
end
|
161
416
|
|
162
417
|
##
|
@@ -199,27 +454,39 @@ module GoodData
|
|
199
454
|
folders_maql + "\n" + maql + "SYNCHRONIZE {#{identifier}};\n"
|
200
455
|
end
|
201
456
|
|
202
|
-
# Load given file into a data set described by the given schema
|
203
|
-
#
|
204
457
|
def upload(path, project = nil, mode = "FULL")
|
458
|
+
if path =~ URI::regexp
|
459
|
+
Tempfile.open('remote_file') do |temp|
|
460
|
+
temp << open(path).read
|
461
|
+
temp.flush
|
462
|
+
upload_data(temp, project, mode)
|
463
|
+
end
|
464
|
+
else
|
465
|
+
upload_data(path, project, mode)
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
# Load given file into a data set described by the given schema
|
470
|
+
def upload_data(path, project = nil, mode = "FULL")
|
205
471
|
path = path.path if path.respond_to? :path
|
206
|
-
|
472
|
+
|
473
|
+
inline_data = path.is_a?(String) ? false : true
|
474
|
+
|
207
475
|
project = GoodData.project unless project
|
208
476
|
|
209
477
|
# create a temporary zip file
|
210
478
|
dir = Dir.mktmpdir
|
211
|
-
Zip::
|
479
|
+
Zip::File.open("#{dir}/upload.zip", Zip::File::CREATE) do |zip|
|
212
480
|
# TODO make sure schema columns match CSV column names
|
213
481
|
zip.get_output_stream('upload_info.json') { |f| f.puts JSON.pretty_generate(to_manifest(mode)) }
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
else
|
219
|
-
transform_row(header, row)
|
482
|
+
if inline_data
|
483
|
+
zip.get_output_stream('data.csv') do |f|
|
484
|
+
path.each do |row|
|
485
|
+
f.puts row.to_csv
|
220
486
|
end
|
221
|
-
f.puts output.to_csv
|
222
487
|
end
|
488
|
+
else
|
489
|
+
zip.add('data.csv', path)
|
223
490
|
end
|
224
491
|
end
|
225
492
|
|
@@ -234,6 +501,7 @@ module GoodData
|
|
234
501
|
while (GoodData.get(task["pullTask"]["uri"])["taskStatus"] === "RUNNING" || GoodData.get(task["pullTask"]["uri"])["taskStatus"] === "PREPARED") do
|
235
502
|
sleep 30
|
236
503
|
end
|
504
|
+
fail "Load Failed" if (GoodData.get(task["pullTask"]["uri"])["taskStatus"] == "ERROR")
|
237
505
|
puts "Done loading"
|
238
506
|
end
|
239
507
|
|
@@ -322,10 +590,11 @@ module GoodData
|
|
322
590
|
attr_accessor :folder, :name, :title, :schema
|
323
591
|
|
324
592
|
def initialize(hash, schema)
|
593
|
+
super()
|
325
594
|
raise ArgumentError.new("Schema must be provided, got #{schema.class}") unless schema.is_a? Schema
|
326
|
-
@name = hash[
|
327
|
-
@title = hash[
|
328
|
-
@folder = hash[
|
595
|
+
@name = hash[:name] || raise("Data set fields must have their names defined")
|
596
|
+
@title = hash[:title] || hash[:name].humanize
|
597
|
+
@folder = hash[:folder]
|
329
598
|
@schema = schema
|
330
599
|
end
|
331
600
|
|
@@ -334,7 +603,7 @@ module GoodData
|
|
334
603
|
# non-Latin character and then dropping non-alphanumerical characters.
|
335
604
|
#
|
336
605
|
def identifier
|
337
|
-
@identifier ||= "#{self.type_prefix}.#{
|
606
|
+
@identifier ||= "#{self.type_prefix}.#{@schema.name}.#{name}"
|
338
607
|
end
|
339
608
|
|
340
609
|
def to_maql_drop
|
@@ -343,7 +612,7 @@ module GoodData
|
|
343
612
|
|
344
613
|
def visual
|
345
614
|
visual = super
|
346
|
-
visual += ", FOLDER {#{folder_prefix}.#{
|
615
|
+
visual += ", FOLDER {#{folder_prefix}.#{(folder)}}" if folder
|
347
616
|
visual
|
348
617
|
end
|
349
618
|
|
@@ -380,10 +649,10 @@ module GoodData
|
|
380
649
|
end
|
381
650
|
|
382
651
|
def table
|
383
|
-
@table ||= "d_" +
|
652
|
+
@table ||= "d_" + @schema.name + "_" + name
|
384
653
|
end
|
385
654
|
|
386
|
-
def key ; "#{
|
655
|
+
def key ; "#{@name}#{FK_SUFFIX}" ; end
|
387
656
|
|
388
657
|
def to_maql_create
|
389
658
|
maql = "CREATE ATTRIBUTE {#{identifier}} VISUAL (#{visual})" \
|
@@ -413,7 +682,7 @@ module GoodData
|
|
413
682
|
# def initialize(hash, schema)
|
414
683
|
def initialize(hash, attribute, schema)
|
415
684
|
super hash, schema
|
416
|
-
@attribute = attribute || schema.fields.find {|field| field.name === hash[
|
685
|
+
@attribute = attribute || schema.fields.find {|field| field.name === hash[:reference]}
|
417
686
|
end
|
418
687
|
|
419
688
|
def to_maql_create
|
@@ -431,7 +700,7 @@ module GoodData
|
|
431
700
|
end
|
432
701
|
|
433
702
|
def column
|
434
|
-
"#{@attribute.table}.#{LABEL_COLUMN_PREFIX}#{
|
703
|
+
"#{@attribute.table}.#{LABEL_COLUMN_PREFIX}#{name}"
|
435
704
|
end
|
436
705
|
|
437
706
|
alias :inspect_orig :inspect
|
@@ -457,7 +726,7 @@ module GoodData
|
|
457
726
|
end
|
458
727
|
|
459
728
|
def table
|
460
|
-
@table ||= "f_" +
|
729
|
+
@table ||= "f_" + @schema.name
|
461
730
|
end
|
462
731
|
|
463
732
|
def to_maql_create
|
@@ -484,7 +753,7 @@ module GoodData
|
|
484
753
|
end
|
485
754
|
|
486
755
|
def column
|
487
|
-
@column ||= table + '.' + column_prefix +
|
756
|
+
@column ||= table + '.' + column_prefix + name
|
488
757
|
end
|
489
758
|
|
490
759
|
def to_maql_create
|
@@ -508,10 +777,9 @@ module GoodData
|
|
508
777
|
def initialize(column, schema)
|
509
778
|
super column, schema
|
510
779
|
# pp column
|
511
|
-
|
512
|
-
@
|
513
|
-
@
|
514
|
-
@schema_ref = column['schema_reference']
|
780
|
+
@name = column[:name]
|
781
|
+
@reference = column[:reference]
|
782
|
+
@schema_ref = column[:dataset]
|
515
783
|
@schema = schema
|
516
784
|
end
|
517
785
|
|
@@ -521,13 +789,13 @@ module GoodData
|
|
521
789
|
# from the reference key.
|
522
790
|
#
|
523
791
|
def identifier
|
524
|
-
@identifier ||= "#{ATTRIBUTE_PREFIX}.#{
|
792
|
+
@identifier ||= "#{ATTRIBUTE_PREFIX}.#{@schema_ref}.#{@reference}"
|
525
793
|
end
|
526
794
|
|
527
|
-
def key ; "#{
|
795
|
+
def key ; "#{@name}_id" ; end
|
528
796
|
|
529
797
|
def label_column
|
530
|
-
"#{LABEL_PREFIX}.#{
|
798
|
+
"#{LABEL_PREFIX}.#{@schema_ref}.#{@reference}"
|
531
799
|
end
|
532
800
|
|
533
801
|
def to_maql_create
|
@@ -551,40 +819,40 @@ module GoodData
|
|
551
819
|
##
|
552
820
|
# Fact representation of a date.
|
553
821
|
#
|
554
|
-
class DateFact < Fact
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
end
|
822
|
+
# class DateFact < Fact
|
823
|
+
#
|
824
|
+
# attr_accessor :format, :output_format
|
825
|
+
#
|
826
|
+
# def initialize(column, schema)
|
827
|
+
# super column, schema
|
828
|
+
# @output_format = column["format"] || '("dd/MM/yyyy")'
|
829
|
+
# @format = @output_format.gsub('yyyy', '%Y').gsub('MM', '%m').gsub('dd', '%d')
|
830
|
+
# end
|
831
|
+
#
|
832
|
+
# def column_prefix ; DATE_COLUMN_PREFIX ; end
|
833
|
+
# def type_prefix ; DATE_FACT_PREFIX ; end
|
834
|
+
#
|
835
|
+
# def to_csv_header(row)
|
836
|
+
# "#{name}_fact"
|
837
|
+
# end
|
838
|
+
#
|
839
|
+
# def to_csv_data(headers, row)
|
840
|
+
# val = row[name]
|
841
|
+
# val.nil?() ? nil : (Date.strptime(val, format) - BEGINNING_OF_TIMES).to_i
|
842
|
+
# rescue ArgumentError
|
843
|
+
# raise "Value \"#{val}\" for column \"#{name}\" did not match the format: #{format}. " +
|
844
|
+
# "Perhaps you need to add or change the \"format\" key in the data set configuration."
|
845
|
+
# end
|
846
|
+
#
|
847
|
+
# def to_manifest_part(mode)
|
848
|
+
# {
|
849
|
+
# 'populates' => [ identifier ],
|
850
|
+
# 'mode' => mode,
|
851
|
+
# 'columnName' => "#{name}_fact"
|
852
|
+
# }
|
853
|
+
# end
|
854
|
+
#
|
855
|
+
# end
|
588
856
|
|
589
857
|
##
|
590
858
|
# Date as a reference to a date dimension
|
@@ -595,13 +863,13 @@ module GoodData
|
|
595
863
|
|
596
864
|
def initialize(column, schema)
|
597
865
|
super column, schema
|
598
|
-
@output_format = column["format"] || '
|
866
|
+
@output_format = column["format"] || 'dd/MM/yyyy'
|
599
867
|
@format = @output_format.gsub('yyyy', '%Y').gsub('MM', '%m').gsub('dd', '%d')
|
600
|
-
@urn = column[
|
868
|
+
@urn = column[:urn] || "URN:GOODDATA:DATE"
|
601
869
|
end
|
602
870
|
|
603
871
|
def identifier
|
604
|
-
@identifier ||= "#{
|
872
|
+
@identifier ||= "#{@schema_ref}.#{DATE_ATTRIBUTE}"
|
605
873
|
end
|
606
874
|
|
607
875
|
def to_manifest_part(mode)
|
@@ -614,14 +882,14 @@ module GoodData
|
|
614
882
|
}
|
615
883
|
end
|
616
884
|
|
617
|
-
def to_maql_create
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
end
|
885
|
+
# def to_maql_create
|
886
|
+
# # urn:chefs_warehouse_fiscal:date
|
887
|
+
# super_maql = super
|
888
|
+
# maql = ""
|
889
|
+
# # maql = "# Include date dimensions\n"
|
890
|
+
# # maql += "INCLUDE TEMPLATE \"#{urn}\" MODIFY (IDENTIFIER \"#{name}\", TITLE \"#{title || name}\");\n"
|
891
|
+
# maql += super_maql
|
892
|
+
# end
|
625
893
|
|
626
894
|
end
|
627
895
|
|
@@ -677,22 +945,22 @@ module GoodData
|
|
677
945
|
super column, schema
|
678
946
|
@parts = {} ; @facts = [] ; @attributes = []; @references = []
|
679
947
|
|
680
|
-
@facts << @parts[:date_fact] = DateFact.new(column, schema)
|
681
|
-
if column[
|
948
|
+
# @facts << @parts[:date_fact] = DateFact.new(column, schema)
|
949
|
+
if column[:dataset] then
|
682
950
|
@parts[:date_ref] = DateReference.new column, schema
|
683
951
|
@references << @parts[:date_ref]
|
684
952
|
else
|
685
953
|
@attributes << @parts[:date_attr] = DateAttribute.new(column, schema)
|
686
954
|
end
|
687
|
-
if column['datetime'] then
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
end
|
955
|
+
# if column['datetime'] then
|
956
|
+
# puts "*** datetime"
|
957
|
+
# @facts << @parts[:time_fact] = TimeFact.new(column, schema)
|
958
|
+
# if column['schema_reference'] then
|
959
|
+
# @parts[:time_ref] = TimeReference.new column, schema
|
960
|
+
# else
|
961
|
+
# @attributes << @parts[:time_attr] = TimeAttribute.new(column, schema)
|
962
|
+
# end
|
963
|
+
# end
|
696
964
|
end
|
697
965
|
|
698
966
|
def to_maql_create
|
@@ -727,7 +995,7 @@ module GoodData
|
|
727
995
|
end
|
728
996
|
|
729
997
|
def to_maql_create
|
730
|
-
"CREATE FOLDER {#{type_prefix}.#{
|
998
|
+
"CREATE FOLDER {#{type_prefix}.#{name}}" \
|
731
999
|
+ " VISUAL (#{visual}) TYPE #{type};\n"
|
732
1000
|
end
|
733
1001
|
end
|
@@ -750,13 +1018,25 @@ module GoodData
|
|
750
1018
|
|
751
1019
|
class DateDimension < MdObject
|
752
1020
|
|
1021
|
+
def initialize(spec={})
|
1022
|
+
super()
|
1023
|
+
@name = spec[:name]
|
1024
|
+
@title = spec[:title] || @name
|
1025
|
+
@urn = spec[:urn] || "URN:GOODDATA:DATE"
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
|
753
1029
|
def to_maql_create
|
754
|
-
# urn:chefs_warehouse_fiscal:date
|
1030
|
+
# urn = "urn:chefs_warehouse_fiscal:date"
|
1031
|
+
# title = "title"
|
1032
|
+
# name = "name"
|
1033
|
+
|
755
1034
|
maql = ""
|
756
|
-
maql += "INCLUDE TEMPLATE \"#{urn}\" MODIFY (IDENTIFIER \"#{name}\", TITLE \"#{title
|
1035
|
+
maql += "INCLUDE TEMPLATE \"#{@urn}\" MODIFY (IDENTIFIER \"#{@name}\", TITLE \"#{@title}\");"
|
757
1036
|
maql
|
758
1037
|
end
|
1038
|
+
|
759
1039
|
end
|
760
1040
|
|
761
1041
|
end
|
762
|
-
end
|
1042
|
+
end
|