gooddata 0.6.0.pre11 → 0.6.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +12 -1
- data/.yardopts +2 -0
- data/README.md +6 -3
- data/Rakefile +24 -7
- data/gooddata +2 -2
- data/gooddata.gemspec +4 -3
- data/lib/gooddata.rb +17 -12
- data/lib/gooddata/bricks/base_downloader.rb +7 -7
- data/lib/gooddata/bricks/brick.rb +7 -8
- data/lib/gooddata/bricks/bricks.rb +4 -1
- data/lib/gooddata/bricks/middleware/base_middleware.rb +2 -2
- data/lib/gooddata/bricks/middleware/bench_middleware.rb +5 -6
- data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +21 -22
- data/lib/gooddata/bricks/middleware/fs_upload_middleware.rb +3 -4
- data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +14 -14
- data/lib/gooddata/bricks/middleware/logger_middleware.rb +6 -6
- data/lib/gooddata/bricks/middleware/middleware.rb +4 -1
- data/lib/gooddata/bricks/middleware/restforce_middleware.rb +29 -32
- data/lib/gooddata/bricks/middleware/stdout_middleware.rb +5 -5
- data/lib/gooddata/bricks/middleware/twitter_middleware.rb +6 -8
- data/lib/gooddata/bricks/utils.rb +3 -3
- data/lib/gooddata/cli/cli.rb +4 -2
- data/lib/gooddata/cli/commands/api_cmd.rb +6 -4
- data/lib/gooddata/cli/commands/auth_cmd.rb +5 -3
- data/lib/gooddata/cli/commands/console_cmd.rb +1 -1
- data/lib/gooddata/cli/commands/process_cmd.rb +6 -4
- data/lib/gooddata/cli/commands/profile_cmd.rb +5 -3
- data/lib/gooddata/cli/commands/project_cmd.rb +24 -22
- data/lib/gooddata/cli/commands/run_ruby_cmd.rb +12 -10
- data/lib/gooddata/cli/commands/scaffold_cmd.rb +8 -6
- data/lib/gooddata/cli/hooks.rb +4 -2
- data/lib/gooddata/cli/shared.rb +3 -1
- data/lib/gooddata/cli/terminal.rb +16 -0
- data/lib/gooddata/client.rb +28 -22
- data/lib/gooddata/commands/api.rb +43 -26
- data/lib/gooddata/commands/auth.rb +22 -53
- data/lib/gooddata/commands/base.rb +2 -0
- data/lib/gooddata/commands/commands.rb +3 -0
- data/lib/gooddata/commands/datasets.rb +39 -136
- data/lib/gooddata/commands/process.rb +134 -130
- data/lib/gooddata/commands/profile.rb +2 -0
- data/lib/gooddata/commands/projects.rb +91 -129
- data/lib/gooddata/commands/runners.rb +11 -11
- data/lib/gooddata/commands/scaffold.rb +28 -26
- data/lib/gooddata/connection.rb +61 -68
- data/lib/gooddata/core/core.rb +1 -2
- data/lib/gooddata/data/data.rb +7 -0
- data/lib/gooddata/data/guesser.rb +114 -0
- data/lib/gooddata/exceptions/command_failed.rb +7 -0
- data/lib/gooddata/exceptions/exceptions.rb +7 -0
- data/lib/gooddata/{exceptions.rb → exceptions/project_not_found.rb} +2 -2
- data/lib/gooddata/extensions/big_decimal.rb +5 -0
- data/lib/gooddata/extract.rb +2 -0
- data/lib/gooddata/goodzilla/goodzilla.rb +11 -12
- data/lib/gooddata/helpers.rb +49 -35
- data/lib/gooddata/models/attribute.rb +7 -5
- data/lib/gooddata/models/dashboard.rb +44 -45
- data/lib/gooddata/models/data_result.rb +10 -13
- data/lib/gooddata/models/data_set.rb +6 -6
- data/lib/gooddata/models/display_form.rb +4 -4
- data/lib/gooddata/models/empty_result.rb +4 -3
- data/lib/gooddata/models/fact.rb +5 -5
- data/lib/gooddata/models/links.rb +3 -1
- data/lib/gooddata/models/metadata.rb +34 -32
- data/lib/gooddata/models/metric.rb +33 -34
- data/lib/gooddata/models/model.rb +165 -173
- data/lib/gooddata/models/models.rb +3 -0
- data/lib/gooddata/models/process.rb +18 -17
- data/lib/gooddata/models/profile.rb +3 -1
- data/lib/gooddata/models/project.rb +107 -35
- data/lib/gooddata/models/project_metadata.rb +12 -12
- data/lib/gooddata/models/report.rb +31 -30
- data/lib/gooddata/models/report_data_result.rb +22 -19
- data/lib/gooddata/models/report_definition.rb +101 -80
- data/lib/gooddata/version.rb +5 -3
- data/lib/templates/bricks/brick.rb.erb +3 -3
- data/lib/templates/bricks/main.rb.erb +3 -2
- data/lib/templates/project/Goodfile.erb +2 -2
- data/lib/templates/project/model/model.rb.erb +19 -19
- data/spec/data/.gooddata +4 -0
- data/spec/helpers/blueprint_helper.rb +2 -2
- data/spec/helpers/cli_helper.rb +28 -0
- data/spec/helpers/connection_helper.rb +2 -2
- data/spec/integration/command_projects_spec.rb +1 -1
- data/spec/integration/create_from_template_spec.rb +12 -0
- data/spec/integration/full_project_spec.rb +2 -2
- data/spec/integration/partial_md_export_import_spec.rb +36 -0
- data/spec/logging_in_logging_out_spec.rb +1 -1
- data/spec/spec_helper.rb +29 -2
- data/spec/unit/cli/cli_spec.rb +3 -3
- data/spec/unit/cli/commands/cmd_api_spec.rb +21 -4
- data/spec/unit/cli/commands/cmd_auth_spec.rb +2 -4
- data/spec/unit/cli/commands/cmd_process_spec.rb +20 -4
- data/spec/unit/cli/commands/cmd_profile_spec.rb +9 -4
- data/spec/unit/cli/commands/cmd_project_spec.rb +53 -4
- data/spec/unit/cli/commands/cmd_run_ruby_spec.rb +2 -4
- data/spec/unit/cli/commands/cmd_scaffold_spec.rb +14 -4
- data/spec/unit/commands/command_api_spec.rb +21 -2
- data/spec/unit/commands/command_auth_spec.rb +62 -1
- data/spec/unit/commands/command_dataset_spec.rb +31 -3
- data/spec/unit/commands/command_process_spec.rb +75 -1
- data/spec/unit/commands/command_profile_spec.rb +7 -1
- data/spec/unit/commands/command_projects_spec.rb +1 -1
- data/spec/unit/commands/command_scaffold_spec.rb +46 -1
- data/spec/unit/core/connection_spec.rb +1 -0
- data/spec/unit/data/guesser_spec.rb +54 -0
- data/spec/unit/helpers_spec.rb +47 -0
- data/spec/unit/model/schema_builder_spec.rb +2 -0
- data/spec/unit/model/tools_spec.rb +89 -0
- data/test/test_upload.rb +39 -15
- metadata +98 -75
- data/test/test_commands.rb +0 -85
- data/test/test_guessing.rb +0 -46
- data/test/test_model.rb +0 -81
- data/test/test_rest_api_basic.rb +0 -41
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require_relative 'data_result.rb'
|
|
2
4
|
|
|
3
5
|
module GoodData
|
|
4
6
|
class EmptyResult < DataResult
|
|
5
|
-
|
|
6
7
|
def initialize(data, options = {})
|
|
7
8
|
super(data)
|
|
8
9
|
@options = options
|
|
@@ -10,7 +11,7 @@ module GoodData
|
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
def to_s
|
|
13
|
-
|
|
14
|
+
'No Data'
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def assemble_table
|
data/lib/gooddata/models/fact.rb
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
# encoding: UTF-8
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
class Fact < GoodData::MdObject
|
|
3
|
+
require_relative 'metadata'
|
|
5
4
|
|
|
5
|
+
module GoodData
|
|
6
|
+
class Fact < GoodData::MdObject
|
|
6
7
|
root_key :fact
|
|
7
8
|
|
|
8
9
|
class << self
|
|
9
10
|
def [](id)
|
|
10
11
|
if id == :all
|
|
11
12
|
GoodData.get(GoodData.project.md['query'] + '/facts/')['query']['entries']
|
|
12
|
-
else
|
|
13
|
+
else
|
|
13
14
|
super
|
|
14
15
|
end
|
|
15
16
|
end
|
|
16
17
|
end
|
|
17
|
-
|
|
18
18
|
end
|
|
19
19
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
1
3
|
module GoodData
|
|
2
4
|
class Links
|
|
3
5
|
attr_reader :data
|
|
@@ -8,7 +10,7 @@ module GoodData
|
|
|
8
10
|
category = item['category']
|
|
9
11
|
if @data[category] then
|
|
10
12
|
if @data[category]['category'] == category then
|
|
11
|
-
@data[category] = {
|
|
13
|
+
@data[category] = {@data[category]['identifier'] => @data[category]}
|
|
12
14
|
end
|
|
13
15
|
@data[category][item['identifier']] = item
|
|
14
16
|
else
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require_relative 'model'
|
|
2
4
|
|
|
3
5
|
module GoodData
|
|
4
6
|
class MdObject
|
|
@@ -7,25 +9,25 @@ module GoodData
|
|
|
7
9
|
|
|
8
10
|
class << self
|
|
9
11
|
def root_key(a_key)
|
|
10
|
-
define_method :root_key, Proc.new { a_key.to_s}
|
|
12
|
+
define_method :root_key, Proc.new { a_key.to_s }
|
|
11
13
|
end
|
|
12
|
-
|
|
14
|
+
|
|
13
15
|
def [](id)
|
|
14
16
|
raise "Cannot search for nil #{self.class}" unless id
|
|
15
17
|
uri = if id.is_a? Integer or id =~ /^\d+$/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
"#{GoodData.project.md[MD_OBJ_CTG]}/#{id}"
|
|
19
|
+
elsif id !~ /\//
|
|
20
|
+
identifier_to_uri id
|
|
21
|
+
elsif id =~ /^\//
|
|
22
|
+
id
|
|
23
|
+
else
|
|
24
|
+
raise 'Unexpected object id format: expected numeric ID, identifier with no slashes or an URI starting with a slash'
|
|
25
|
+
end
|
|
24
26
|
self.new(GoodData.get uri) unless uri.nil?
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
def find_by_tag(tag)
|
|
28
|
-
self[:all].find_all {|r| r[
|
|
30
|
+
self[:all].find_all { |r| r['tags'].split(',').include?(tag) }
|
|
29
31
|
end
|
|
30
32
|
|
|
31
33
|
def get_by_id(id)
|
|
@@ -36,27 +38,26 @@ module GoodData
|
|
|
36
38
|
def find_first_by_title(title)
|
|
37
39
|
all = self[:all]
|
|
38
40
|
item = if title.is_a?(Regexp)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
self[item[
|
|
41
|
+
all.find { |r| r['title'] =~ title }
|
|
42
|
+
else
|
|
43
|
+
all.find { |r| r['title'] == title }
|
|
44
|
+
end
|
|
45
|
+
self[item['link']] unless item.nil?
|
|
44
46
|
end
|
|
45
47
|
|
|
46
48
|
def identifier_to_uri(*ids)
|
|
47
|
-
raise NoProjectError.new
|
|
48
|
-
uri
|
|
49
|
-
response = GoodData.post uri, {
|
|
49
|
+
raise NoProjectError.new 'Connect to a project before searching for an object' unless GoodData.project
|
|
50
|
+
uri = GoodData.project.md[IDENTIFIERS_CFG]
|
|
51
|
+
response = GoodData.post uri, {'identifierToUri' => ids}
|
|
50
52
|
if response['identifiers'].empty?
|
|
51
53
|
nil
|
|
52
54
|
else
|
|
53
|
-
ids = response['identifiers'].map {|x| x['uri']}
|
|
55
|
+
ids = response['identifiers'].map { |x| x['uri'] }
|
|
54
56
|
ids.count == 1 ? ids.first : ids
|
|
55
57
|
end
|
|
56
58
|
end
|
|
57
59
|
|
|
58
60
|
alias :id_to_uri :identifier_to_uri
|
|
59
|
-
|
|
60
61
|
end
|
|
61
62
|
|
|
62
63
|
def initialize(json)
|
|
@@ -66,7 +67,7 @@ module GoodData
|
|
|
66
67
|
def delete
|
|
67
68
|
if saved?
|
|
68
69
|
GoodData.delete(uri)
|
|
69
|
-
meta.delete(
|
|
70
|
+
meta.delete('uri')
|
|
70
71
|
# ["uri"] = nil
|
|
71
72
|
end
|
|
72
73
|
end
|
|
@@ -107,19 +108,19 @@ module GoodData
|
|
|
107
108
|
end
|
|
108
109
|
|
|
109
110
|
def title=(a_title)
|
|
110
|
-
data[
|
|
111
|
+
data['meta']['title'] = a_title
|
|
111
112
|
end
|
|
112
113
|
|
|
113
114
|
def summary=(a_summary)
|
|
114
|
-
data[
|
|
115
|
+
data['meta']['summary'] = a_summary
|
|
115
116
|
end
|
|
116
117
|
|
|
117
118
|
def tags
|
|
118
|
-
data[
|
|
119
|
+
data['meta']['tags']
|
|
119
120
|
end
|
|
120
121
|
|
|
121
122
|
def tags=(list_of_tags)
|
|
122
|
-
data[
|
|
123
|
+
data['meta']['tags'] = list_of_tags
|
|
123
124
|
end
|
|
124
125
|
|
|
125
126
|
def meta
|
|
@@ -136,12 +137,12 @@ module GoodData
|
|
|
136
137
|
|
|
137
138
|
def get_usedby
|
|
138
139
|
result = GoodData.get "#{GoodData.project.md['usedby2']}/#{obj_id}"
|
|
139
|
-
result[
|
|
140
|
+
result['entries']
|
|
140
141
|
end
|
|
141
142
|
|
|
142
143
|
def get_using
|
|
143
144
|
result = GoodData.get "#{GoodData.project.md['using2']}/#{obj_id}"
|
|
144
|
-
result[
|
|
145
|
+
result['entries']
|
|
145
146
|
end
|
|
146
147
|
|
|
147
148
|
def to_json
|
|
@@ -153,7 +154,8 @@ module GoodData
|
|
|
153
154
|
end
|
|
154
155
|
|
|
155
156
|
def data
|
|
156
|
-
raw_data
|
|
157
|
+
key = methods.include?(:root_key) ? root_key : raw_data.keys.first
|
|
158
|
+
raw_data[key]
|
|
157
159
|
end
|
|
158
160
|
|
|
159
161
|
def saved?
|
|
@@ -161,13 +163,13 @@ module GoodData
|
|
|
161
163
|
end
|
|
162
164
|
|
|
163
165
|
def save
|
|
164
|
-
fail(
|
|
166
|
+
fail('Validation failed') unless validate
|
|
165
167
|
|
|
166
168
|
if saved?
|
|
167
169
|
GoodData.put(uri, to_json)
|
|
168
170
|
else
|
|
169
171
|
result = GoodData.post(GoodData.project.md['obj'], to_json)
|
|
170
|
-
saved_object = self.class[result[
|
|
172
|
+
saved_object = self.class[result['uri']]
|
|
171
173
|
@json = saved_object.raw_data
|
|
172
174
|
end
|
|
173
175
|
self
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require_relative 'metadata'
|
|
4
|
+
require_relative '../goodzilla/goodzilla'
|
|
3
5
|
|
|
4
6
|
module GoodData
|
|
5
7
|
# Metric representation
|
|
6
8
|
class Metric < GoodData::MdObject
|
|
7
|
-
|
|
8
9
|
root_key :metric
|
|
9
10
|
|
|
10
11
|
class << self
|
|
11
12
|
def [](id)
|
|
12
13
|
if id == :all
|
|
13
14
|
GoodData.get(GoodData.project.md['query'] + '/metrics/')['query']['entries']
|
|
14
|
-
else
|
|
15
|
+
else
|
|
15
16
|
super
|
|
16
17
|
end
|
|
17
18
|
end
|
|
@@ -32,43 +33,43 @@ module GoodData
|
|
|
32
33
|
else
|
|
33
34
|
title = options[:title]
|
|
34
35
|
summary = options[:summary]
|
|
35
|
-
expression = options[:expression] || fail(
|
|
36
|
+
expression = options[:expression] || fail('Metric has to have its expression defined')
|
|
36
37
|
extended_notation = options[:extended_notation] || false
|
|
37
38
|
end
|
|
38
39
|
|
|
39
40
|
expression = if extended_notation
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
dict = {
|
|
42
|
+
:facts => GoodData::Fact[:all].reduce({}) { |memo, item| memo[item['title']] = item['link']; memo },
|
|
43
|
+
:attributes => GoodData::Attribute[:all].reduce({}) { |memo, item| memo[item['title']] = item['link']; memo },
|
|
44
|
+
:metrics => GoodData::Metric[:all].reduce({}) { |memo, item| memo[item['title']] = item['link']; memo },
|
|
45
|
+
}
|
|
46
|
+
interpolated_metric = GoodData::SmallGoodZilla.interpolate_metric(expression, dict)
|
|
47
|
+
interpolated_metric
|
|
48
|
+
else
|
|
49
|
+
expression
|
|
50
|
+
end
|
|
50
51
|
|
|
51
52
|
Metric.new({
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
53
|
+
'metric' => {
|
|
54
|
+
'content' => {
|
|
55
|
+
'format' => '#,##0',
|
|
56
|
+
'expression' => expression
|
|
57
|
+
},
|
|
58
|
+
'meta' => {
|
|
59
|
+
'tags' => '',
|
|
60
|
+
'summary' => summary,
|
|
61
|
+
'title' => title,
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
})
|
|
64
65
|
end
|
|
65
66
|
|
|
66
67
|
def execute(expression, options={})
|
|
67
68
|
m = if expression.is_a?(String)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
GoodData::Metric.create({:title => 'Temporary metric to be deleted', :expression => expression}.merge(options))
|
|
70
|
+
else
|
|
71
|
+
GoodData::Metric.create({:title => 'Temporary metric to be deleted'}.merge(expression))
|
|
72
|
+
end
|
|
72
73
|
m.execute
|
|
73
74
|
end
|
|
74
75
|
|
|
@@ -79,7 +80,6 @@ module GoodData
|
|
|
79
80
|
execute(expression.merge({:extended_notation => true}))
|
|
80
81
|
end
|
|
81
82
|
end
|
|
82
|
-
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
def execute
|
|
@@ -88,13 +88,12 @@ module GoodData
|
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
def validate
|
|
91
|
-
fail
|
|
91
|
+
fail 'Meric needs to have title' if title.nil?
|
|
92
92
|
true
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
def is_metric?
|
|
96
96
|
true
|
|
97
97
|
end
|
|
98
|
-
|
|
99
98
|
end
|
|
100
99
|
end
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require_relative '../helpers'
|
|
4
|
+
|
|
1
5
|
require 'open-uri'
|
|
2
6
|
require 'active_support/all'
|
|
7
|
+
|
|
3
8
|
##
|
|
4
9
|
# Module containing classes that counter-part GoodData server-side meta-data
|
|
5
10
|
# elements, including the server-side data model.
|
|
6
11
|
#
|
|
7
12
|
module GoodData
|
|
8
|
-
|
|
9
13
|
module Model
|
|
10
|
-
|
|
11
14
|
# GoodData REST API categories
|
|
12
15
|
LDM_CTG = 'ldm'
|
|
13
16
|
LDM_MANAGE_CTG = 'ldm-manage'
|
|
@@ -24,7 +27,7 @@ module GoodData
|
|
|
24
27
|
LABEL_PREFIX = 'label'
|
|
25
28
|
FACT_PREFIX = 'fact'
|
|
26
29
|
DATE_FACT_PREFIX = 'dt'
|
|
27
|
-
DATE_ATTRIBUTE =
|
|
30
|
+
DATE_ATTRIBUTE = 'date'
|
|
28
31
|
DATE_ATTRIBUTE_DEFAULT_DISPLAY_FORM = 'mdyy'
|
|
29
32
|
TIME_FACT_PREFIX = 'tm.dt'
|
|
30
33
|
TIME_ATTRIBUTE_PREFIX = 'attr.time'
|
|
@@ -83,13 +86,13 @@ module GoodData
|
|
|
83
86
|
pull = {'pullIntegration' => File.basename(dir)}
|
|
84
87
|
link = project.md.links('etl')['pull']
|
|
85
88
|
task = GoodData.post link, pull
|
|
86
|
-
while
|
|
89
|
+
while GoodData.get(task['pullTask']['uri'])['taskStatus'] === 'RUNNING' || GoodData.get(task['pullTask']['uri'])['taskStatus'] === 'PREPARED'
|
|
87
90
|
sleep 30
|
|
88
91
|
end
|
|
89
|
-
if
|
|
92
|
+
if GoodData.get(task['pullTask']['uri'])['taskStatus'] == 'ERROR'
|
|
90
93
|
s = StringIO.new
|
|
91
94
|
GoodData.download_from_user_webdav(File.basename(dir) + '/upload_status.json', s)
|
|
92
|
-
js =
|
|
95
|
+
js = MultiJson.load(s.string)
|
|
93
96
|
fail "Load Failed with error #{JSON.pretty_generate(js)}"
|
|
94
97
|
end
|
|
95
98
|
end
|
|
@@ -100,20 +103,18 @@ module GoodData
|
|
|
100
103
|
d = Marshal.load(Marshal.dump(a_schema_blueprint))
|
|
101
104
|
d[:columns] = d[:columns] + b_schema_blueprint[:columns]
|
|
102
105
|
d[:columns].uniq!
|
|
103
|
-
columns_that_failed_to_merge = d[:columns].group_by {|x| x[:name]}.map {|k, v| [k, v.count]}.find_all {|x| x[1] > 1}
|
|
106
|
+
columns_that_failed_to_merge = d[:columns].group_by { |x| x[:name] }.map { |k, v| [k, v.count] }.find_all { |x| x[1] > 1 }
|
|
104
107
|
fail "Columns #{columns_that_failed_to_merge} failed to merge. When merging columns with the same name they have to be identical." unless columns_that_failed_to_merge.empty?
|
|
105
108
|
d
|
|
106
109
|
end
|
|
107
|
-
|
|
108
110
|
end
|
|
109
111
|
|
|
110
112
|
class ProjectBlueprint
|
|
111
|
-
|
|
112
113
|
attr_accessor :data
|
|
113
114
|
|
|
114
115
|
def self.from_json(spec)
|
|
115
116
|
if spec.is_a?(String)
|
|
116
|
-
ProjectBlueprint.new(
|
|
117
|
+
ProjectBlueprint.new(MultiJson.load(File.read(spec), :symbolize_keys => true))
|
|
117
118
|
else
|
|
118
119
|
ProjectBlueprint.new(spec)
|
|
119
120
|
end
|
|
@@ -140,7 +141,7 @@ module GoodData
|
|
|
140
141
|
end
|
|
141
142
|
|
|
142
143
|
def remove_dataset(dataset_name)
|
|
143
|
-
x = data[:datasets].find {|d| d[:name] == dataset_name}
|
|
144
|
+
x = data[:datasets].find { |d| d[:name] == dataset_name }
|
|
144
145
|
index = data[:datasets].index(x)
|
|
145
146
|
data[:datasets].delete_at(index)
|
|
146
147
|
end
|
|
@@ -205,28 +206,26 @@ module GoodData
|
|
|
205
206
|
|
|
206
207
|
def to_wire_model
|
|
207
208
|
{
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
209
|
+
'diffRequest' => {
|
|
210
|
+
'targetModel' => {
|
|
211
|
+
'projectModel' => {
|
|
212
|
+
'datasets' => datasets.map { |d| d.to_wire_model },
|
|
213
|
+
'dateDimensions' => date_dimensions.map { |d|
|
|
214
|
+
{
|
|
215
|
+
'dateDimension' => {
|
|
216
|
+
'name' => d[:name],
|
|
217
|
+
'title' => d[:title] || d[:name].humanize
|
|
218
|
+
}
|
|
219
|
+
} }
|
|
220
|
+
}}}}
|
|
220
221
|
end
|
|
221
222
|
|
|
222
223
|
def to_hash
|
|
223
224
|
@data
|
|
224
225
|
end
|
|
225
|
-
|
|
226
226
|
end
|
|
227
227
|
|
|
228
228
|
class SchemaBlueprint
|
|
229
|
-
|
|
230
229
|
attr_accessor :data
|
|
231
230
|
|
|
232
231
|
def change(&block)
|
|
@@ -243,8 +242,8 @@ module GoodData
|
|
|
243
242
|
|
|
244
243
|
def upload(source, options={})
|
|
245
244
|
project = options[:project] || GoodData.project
|
|
246
|
-
fail
|
|
247
|
-
mode = options[:load] ||
|
|
245
|
+
fail 'You have to specify a project into which you want to load.' if project.nil?
|
|
246
|
+
mode = options[:load] || 'FULL'
|
|
248
247
|
project.upload(source, to_schema, mode)
|
|
249
248
|
end
|
|
250
249
|
|
|
@@ -271,7 +270,7 @@ module GoodData
|
|
|
271
270
|
end
|
|
272
271
|
|
|
273
272
|
def has_anchor?
|
|
274
|
-
columns.any? { |c| c[:type].to_s ==
|
|
273
|
+
columns.any? { |c| c[:type].to_s == 'anchor' }
|
|
275
274
|
end
|
|
276
275
|
|
|
277
276
|
def anchor
|
|
@@ -335,17 +334,14 @@ module GoodData
|
|
|
335
334
|
def ==(other)
|
|
336
335
|
to_hash == other.to_hash
|
|
337
336
|
end
|
|
338
|
-
|
|
339
337
|
end
|
|
340
338
|
|
|
341
339
|
class ProjectBuilder
|
|
342
|
-
|
|
343
340
|
attr_reader :title, :datasets, :reports, :metrics, :uploads, :users, :assert_report, :date_dimensions
|
|
344
341
|
|
|
345
342
|
class << self
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
pb = ProjectBuilder.new
|
|
343
|
+
def create_from_data(blueprint, title = 'Title')
|
|
344
|
+
pb = ProjectBuilder.new(title)
|
|
349
345
|
pb.data = blueprint.to_hash
|
|
350
346
|
pb
|
|
351
347
|
end
|
|
@@ -355,7 +351,6 @@ module GoodData
|
|
|
355
351
|
block.call(pb)
|
|
356
352
|
pb
|
|
357
353
|
end
|
|
358
|
-
|
|
359
354
|
end
|
|
360
355
|
|
|
361
356
|
def initialize(title)
|
|
@@ -370,8 +365,14 @@ module GoodData
|
|
|
370
365
|
@date_dimensions = []
|
|
371
366
|
end
|
|
372
367
|
|
|
373
|
-
def add_date_dimension(name, options={})
|
|
374
|
-
|
|
368
|
+
def add_date_dimension(name, options = {})
|
|
369
|
+
dimension = {
|
|
370
|
+
urn: options[:urn],
|
|
371
|
+
name: name,
|
|
372
|
+
title: options[:title]
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@date_dimensions << dimension
|
|
375
376
|
end
|
|
376
377
|
|
|
377
378
|
def add_dataset(name, &block)
|
|
@@ -403,12 +404,12 @@ module GoodData
|
|
|
403
404
|
end
|
|
404
405
|
|
|
405
406
|
def load_metrics(file)
|
|
406
|
-
new_metrics =
|
|
407
|
+
new_metrics = MultiJson.load(open(file).read, :symbolize_keys => true)
|
|
407
408
|
@metrics = @metrics + new_metrics
|
|
408
409
|
end
|
|
409
410
|
|
|
410
411
|
def load_datasets(file)
|
|
411
|
-
new_metrics =
|
|
412
|
+
new_metrics = MultiJson.load(open(file).read, :symbolize_keys => true)
|
|
412
413
|
@datasets = @datasets + new_metrics
|
|
413
414
|
end
|
|
414
415
|
|
|
@@ -417,12 +418,12 @@ module GoodData
|
|
|
417
418
|
end
|
|
418
419
|
|
|
419
420
|
def upload(data, options={})
|
|
420
|
-
mode = options[:mode] ||
|
|
421
|
+
mode = options[:mode] || 'FULL'
|
|
421
422
|
dataset = options[:dataset]
|
|
422
423
|
@uploads << {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
424
|
+
:source => data,
|
|
425
|
+
:mode => mode,
|
|
426
|
+
:dataset => dataset
|
|
426
427
|
}
|
|
427
428
|
end
|
|
428
429
|
|
|
@@ -442,26 +443,24 @@ module GoodData
|
|
|
442
443
|
|
|
443
444
|
def to_hash
|
|
444
445
|
{
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
446
|
+
:title => @title,
|
|
447
|
+
:datasets => @datasets,
|
|
448
|
+
:uploads => @uploads,
|
|
449
|
+
:dashboards => @dashboards,
|
|
450
|
+
:metrics => @metrics,
|
|
451
|
+
:reports => @reports,
|
|
452
|
+
:users => @users,
|
|
453
|
+
:assert_tests => @assert_tests,
|
|
454
|
+
:date_dimensions => @date_dimensions
|
|
454
455
|
}
|
|
455
456
|
end
|
|
456
457
|
|
|
457
458
|
def get_dataset(name)
|
|
458
459
|
datasets.find { |d| d.name == name }
|
|
459
460
|
end
|
|
460
|
-
|
|
461
461
|
end
|
|
462
462
|
|
|
463
463
|
class DashboardBuilder
|
|
464
|
-
|
|
465
464
|
def initialize(title)
|
|
466
465
|
@title = title
|
|
467
466
|
@tabs = []
|
|
@@ -476,14 +475,13 @@ module GoodData
|
|
|
476
475
|
|
|
477
476
|
def to_hash
|
|
478
477
|
{
|
|
479
|
-
|
|
480
|
-
|
|
478
|
+
:name => @name,
|
|
479
|
+
:tabs => @tabs.map { |tab| tab.to_hash }
|
|
481
480
|
}
|
|
482
481
|
end
|
|
483
482
|
end
|
|
484
483
|
|
|
485
484
|
class TabBuilder
|
|
486
|
-
|
|
487
485
|
def initialize(title)
|
|
488
486
|
@title = title
|
|
489
487
|
@stuff = []
|
|
@@ -495,31 +493,27 @@ module GoodData
|
|
|
495
493
|
|
|
496
494
|
def to_hash
|
|
497
495
|
{
|
|
498
|
-
|
|
499
|
-
|
|
496
|
+
:title => @title,
|
|
497
|
+
:items => @stuff
|
|
500
498
|
}
|
|
501
499
|
end
|
|
502
|
-
|
|
503
500
|
end
|
|
504
501
|
|
|
505
502
|
class SchemaBuilder
|
|
506
|
-
|
|
507
503
|
attr_accessor :data
|
|
508
504
|
|
|
509
505
|
class << self
|
|
510
|
-
|
|
511
506
|
def create_from_data(blueprint)
|
|
512
507
|
sc = SchemaBuilder.new
|
|
513
508
|
sc.data = blueprint.to_hash
|
|
514
509
|
sc
|
|
515
510
|
end
|
|
516
|
-
|
|
517
511
|
end
|
|
518
512
|
|
|
519
513
|
def initialize(name=nil)
|
|
520
514
|
@data = {
|
|
521
|
-
|
|
522
|
-
|
|
515
|
+
:name => name,
|
|
516
|
+
:columns => []
|
|
523
517
|
}
|
|
524
518
|
end
|
|
525
519
|
|
|
@@ -575,20 +569,17 @@ module GoodData
|
|
|
575
569
|
def to_schema
|
|
576
570
|
Schema.new(to_hash)
|
|
577
571
|
end
|
|
578
|
-
|
|
579
572
|
end
|
|
580
573
|
|
|
581
574
|
class ProjectCreator
|
|
582
|
-
|
|
583
575
|
class << self
|
|
584
576
|
def migrate(options={})
|
|
585
|
-
|
|
586
|
-
spec = options[:spec] || fail("You need to provide spec for migration")
|
|
577
|
+
spec = options[:spec] || fail('You need to provide spec for migration')
|
|
587
578
|
spec = spec.to_hash
|
|
588
579
|
|
|
589
580
|
token = options[:token]
|
|
590
581
|
project = options[:project] || GoodData::Project.create(:title => spec[:title], :auth_token => token)
|
|
591
|
-
fail(
|
|
582
|
+
fail('You need to specify token for project creation') if token.nil? && project.nil?
|
|
592
583
|
|
|
593
584
|
begin
|
|
594
585
|
GoodData.with_project(project) do |p|
|
|
@@ -615,8 +606,9 @@ module GoodData
|
|
|
615
606
|
bp = ProjectBlueprint.new(spec)
|
|
616
607
|
# schema = Schema.load(schema) unless schema.respond_to?(:to_maql_create)
|
|
617
608
|
# project = GoodData.project unless project
|
|
618
|
-
|
|
619
|
-
|
|
609
|
+
uri = "/gdc/projects/#{GoodData.project.pid}/model/diff"
|
|
610
|
+
result = GoodData.post(uri, bp.to_wire_model)
|
|
611
|
+
link = result['asyncTask']['link']['poll']
|
|
620
612
|
response = GoodData.get(link, :process => false)
|
|
621
613
|
# pp response
|
|
622
614
|
while response.code != 200
|
|
@@ -630,9 +622,9 @@ module GoodData
|
|
|
630
622
|
response = GoodData.get(link)
|
|
631
623
|
ldm_links = GoodData.get project.md[LDM_CTG]
|
|
632
624
|
ldm_uri = Links.new(ldm_links)[LDM_MANAGE_CTG]
|
|
633
|
-
chunks = response[
|
|
625
|
+
chunks = response['projectModelDiff']['updateScripts'].find_all { |script| script['updateScript']['preserveData'] == true && script['updateScript']['cascadeDrops'] == false }.map { |x| x['updateScript']['maqlDdlChunks'] }.flatten
|
|
634
626
|
chunks.each do |chunk|
|
|
635
|
-
GoodData.post ldm_uri, {
|
|
627
|
+
GoodData.post ldm_uri, {'manage' => {'maql' => chunk}}
|
|
636
628
|
end
|
|
637
629
|
|
|
638
630
|
bp.datasets.each do |ds|
|
|
@@ -669,7 +661,7 @@ module GoodData
|
|
|
669
661
|
def load(project, spec)
|
|
670
662
|
if spec.has_key?(:uploads)
|
|
671
663
|
spec[:uploads].each do |load|
|
|
672
|
-
schema = GoodData::Model::Schema.new(spec[:datasets].detect {|d| d[:name] == load[:dataset]})
|
|
664
|
+
schema = GoodData::Model::Schema.new(spec[:datasets].detect { |d| d[:name] == load[:dataset] })
|
|
673
665
|
project.upload(load[:source], schema, load[:mode])
|
|
674
666
|
end
|
|
675
667
|
end
|
|
@@ -716,20 +708,23 @@ module GoodData
|
|
|
716
708
|
Schema.new JSON.load(open(file))
|
|
717
709
|
end
|
|
718
710
|
|
|
719
|
-
def initialize(config, name =
|
|
711
|
+
def initialize(config, name = 'Default Name', title = 'Default Title')
|
|
720
712
|
super()
|
|
721
713
|
@fields = []
|
|
722
714
|
@attributes = []
|
|
723
715
|
@facts = []
|
|
724
716
|
@folders = {
|
|
725
|
-
|
|
726
|
-
|
|
717
|
+
:facts => {},
|
|
718
|
+
:attributes => {}
|
|
727
719
|
}
|
|
728
720
|
@references = []
|
|
729
721
|
@labels = []
|
|
730
722
|
|
|
731
723
|
config[:name] = name unless config[:name]
|
|
732
|
-
config[:title] = config[:
|
|
724
|
+
config[:title] = config[:name] unless config[:title]
|
|
725
|
+
config[:title] = title unless config[:title]
|
|
726
|
+
config[:title] = config[:title].humanize
|
|
727
|
+
|
|
733
728
|
fail 'Schema name not specified' unless config[:name]
|
|
734
729
|
self.name = config[:name]
|
|
735
730
|
self.title = config[:title]
|
|
@@ -739,17 +734,17 @@ module GoodData
|
|
|
739
734
|
def config=(config)
|
|
740
735
|
config[:columns].each do |c|
|
|
741
736
|
case c[:type].to_s
|
|
742
|
-
when
|
|
737
|
+
when 'attribute'
|
|
743
738
|
add_attribute c
|
|
744
|
-
when
|
|
739
|
+
when 'fact'
|
|
745
740
|
add_fact c
|
|
746
|
-
when
|
|
741
|
+
when 'date'
|
|
747
742
|
add_date c
|
|
748
|
-
when
|
|
743
|
+
when 'anchor'
|
|
749
744
|
set_anchor c
|
|
750
|
-
when
|
|
745
|
+
when 'label'
|
|
751
746
|
add_label c
|
|
752
|
-
when
|
|
747
|
+
when 'reference'
|
|
753
748
|
add_reference c
|
|
754
749
|
else
|
|
755
750
|
fail "Unexpected type #{c[:type]} in #{c.inspect}"
|
|
@@ -773,7 +768,7 @@ module GoodData
|
|
|
773
768
|
# Generates MAQL DDL script to drop this data set and included pieces
|
|
774
769
|
#
|
|
775
770
|
def to_maql_drop
|
|
776
|
-
maql =
|
|
771
|
+
maql = ''
|
|
777
772
|
[attributes, facts].each do |obj|
|
|
778
773
|
maql += obj.to_maql_drop
|
|
779
774
|
end
|
|
@@ -784,9 +779,10 @@ module GoodData
|
|
|
784
779
|
# Generates MAQL DDL script to create this data set and included pieces
|
|
785
780
|
#
|
|
786
781
|
def to_maql_create
|
|
782
|
+
# TODO: Use template (.erb)
|
|
787
783
|
maql = "# Create the '#{self.title}' data set\n"
|
|
788
784
|
maql += "CREATE DATASET {#{self.identifier}} VISUAL (TITLE \"#{self.title}\");\n\n"
|
|
789
|
-
[
|
|
785
|
+
[attributes, facts, {1 => @anchor}].each do |objects|
|
|
790
786
|
objects.values.each do |obj|
|
|
791
787
|
maql += "# Create '#{obj.title}' and add it to the '#{self.title}' data set.\n"
|
|
792
788
|
maql += obj.to_maql_create
|
|
@@ -809,7 +805,7 @@ module GoodData
|
|
|
809
805
|
folders_maql + "\n" + maql + "SYNCHRONIZE {#{identifier}};\n"
|
|
810
806
|
end
|
|
811
807
|
|
|
812
|
-
def upload(path, project = nil, mode =
|
|
808
|
+
def upload(path, project = nil, mode = 'FULL')
|
|
813
809
|
if path =~ URI::regexp
|
|
814
810
|
Tempfile.open('remote_file') do |temp|
|
|
815
811
|
temp << open(path).read
|
|
@@ -827,31 +823,32 @@ module GoodData
|
|
|
827
823
|
|
|
828
824
|
# Generates the SLI manifest describing the data loading
|
|
829
825
|
#
|
|
830
|
-
def to_manifest(mode=
|
|
826
|
+
def to_manifest(mode = 'FULL')
|
|
831
827
|
{
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
}
|
|
828
|
+
'dataSetSLIManifest' => {
|
|
829
|
+
'parts' => fields.reduce([]) { |memo, f| val = f.to_manifest_part(mode); memo << val unless val.nil?; memo },
|
|
830
|
+
'dataSet' => self.identifier,
|
|
831
|
+
'file' => 'data.csv', # should be configurable
|
|
832
|
+
'csvParams' => {
|
|
833
|
+
'quoteChar' => '"',
|
|
834
|
+
'escapeChar' => '"',
|
|
835
|
+
'separatorChar' => ',',
|
|
836
|
+
'endOfLine' => "\n"
|
|
842
837
|
}
|
|
838
|
+
}
|
|
843
839
|
}
|
|
844
840
|
end
|
|
845
841
|
|
|
846
842
|
def to_wire_model
|
|
847
843
|
{
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
844
|
+
'dataset' => {
|
|
845
|
+
'identifier' => identifier,
|
|
846
|
+
'title' => title,
|
|
847
|
+
'anchor' => @anchor.to_wire_model,
|
|
848
|
+
'facts' => facts.map { |f| f.to_wire_model },
|
|
849
|
+
'attributes' => attributes.map { |a| a.to_wire_model },
|
|
850
|
+
'references' => references.map { |r| r.is_a?(DateReference) ? r.schema_ref : type_prefix + '.' + r.schema_ref }}
|
|
851
|
+
}
|
|
855
852
|
end
|
|
856
853
|
|
|
857
854
|
private
|
|
@@ -902,14 +899,13 @@ module GoodData
|
|
|
902
899
|
date.parts.values.each { |p| @fields << p }
|
|
903
900
|
date.facts.each { |f| facts << f }
|
|
904
901
|
date.attributes.each { |a| attributes << a }
|
|
905
|
-
date.references.each {|r| references << r}
|
|
902
|
+
date.references.each { |r| references << r }
|
|
906
903
|
end
|
|
907
904
|
|
|
908
905
|
def set_anchor(column)
|
|
909
906
|
@anchor = Anchor.new column, self
|
|
910
907
|
@fields << @anchor
|
|
911
908
|
end
|
|
912
|
-
|
|
913
909
|
end
|
|
914
910
|
|
|
915
911
|
##
|
|
@@ -922,7 +918,9 @@ module GoodData
|
|
|
922
918
|
def initialize(hash, schema)
|
|
923
919
|
super()
|
|
924
920
|
raise ArgumentError.new("Schema must be provided, got #{schema.class}") unless schema.is_a? Schema
|
|
925
|
-
|
|
921
|
+
raise('Data set fields must have their names defined') if hash[:name].nil?
|
|
922
|
+
|
|
923
|
+
@name = hash[:name]
|
|
926
924
|
@title = hash[:title] || hash[:name].humanize
|
|
927
925
|
@folder = hash[:folder]
|
|
928
926
|
@schema = schema
|
|
@@ -985,7 +983,7 @@ module GoodData
|
|
|
985
983
|
end
|
|
986
984
|
|
|
987
985
|
def table
|
|
988
|
-
@table ||=
|
|
986
|
+
@table ||= 'd_' + @schema.name + '_' + name
|
|
989
987
|
end
|
|
990
988
|
|
|
991
989
|
def key;
|
|
@@ -1001,31 +999,30 @@ module GoodData
|
|
|
1001
999
|
|
|
1002
1000
|
def to_manifest_part(mode)
|
|
1003
1001
|
{
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1002
|
+
'referenceKey' => 1,
|
|
1003
|
+
'populates' => [@primary_label.identifier],
|
|
1004
|
+
'mode' => mode,
|
|
1005
|
+
'columnName' => name
|
|
1008
1006
|
}
|
|
1009
1007
|
end
|
|
1010
1008
|
|
|
1011
1009
|
def to_wire_model
|
|
1012
1010
|
{
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1011
|
+
'attribute' => {
|
|
1012
|
+
'identifier' => identifier,
|
|
1013
|
+
'title' => title,
|
|
1014
|
+
'labels' => labels.map do |l|
|
|
1015
|
+
{
|
|
1016
|
+
'label' => {
|
|
1017
|
+
'identifier' => l.identifier,
|
|
1018
|
+
'title' => l.title,
|
|
1019
|
+
'type' => 'GDC.text'
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
end
|
|
1023
|
+
}
|
|
1026
1024
|
}
|
|
1027
1025
|
end
|
|
1028
|
-
|
|
1029
1026
|
end
|
|
1030
1027
|
|
|
1031
1028
|
##
|
|
@@ -1034,30 +1031,31 @@ module GoodData
|
|
|
1034
1031
|
# field
|
|
1035
1032
|
#
|
|
1036
1033
|
class Label < Column
|
|
1037
|
-
|
|
1038
1034
|
attr_accessor :attribute
|
|
1039
1035
|
|
|
1040
|
-
def type_prefix
|
|
1036
|
+
def type_prefix;
|
|
1037
|
+
'label';
|
|
1038
|
+
end
|
|
1041
1039
|
|
|
1042
1040
|
# def initialize(hash, schema)
|
|
1043
1041
|
def initialize(hash, attribute, schema)
|
|
1044
1042
|
super hash, schema
|
|
1045
|
-
attribute = attribute.nil? ? schema.fields.find {|field| field.name === hash[:reference]} : attribute
|
|
1043
|
+
attribute = attribute.nil? ? schema.fields.find { |field| field.name === hash[:reference] } : attribute
|
|
1046
1044
|
@attribute = attribute
|
|
1047
1045
|
attribute.labels << self
|
|
1048
1046
|
end
|
|
1049
1047
|
|
|
1050
1048
|
def to_maql_create
|
|
1051
|
-
|
|
1049
|
+
'# LABEL FROM LABEL'
|
|
1052
1050
|
"ALTER ATTRIBUTE {#{@attribute.identifier}} ADD LABELS {#{identifier}}" \
|
|
1053
1051
|
+ " VISUAL (TITLE #{title.inspect}) AS {#{column}};\n"
|
|
1054
1052
|
end
|
|
1055
1053
|
|
|
1056
1054
|
def to_manifest_part(mode)
|
|
1057
1055
|
{
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1056
|
+
'populates' => [identifier],
|
|
1057
|
+
'mode' => mode,
|
|
1058
|
+
'columnName' => name
|
|
1061
1059
|
}
|
|
1062
1060
|
end
|
|
1063
1061
|
|
|
@@ -1068,7 +1066,7 @@ module GoodData
|
|
|
1068
1066
|
alias :inspect_orig :inspect
|
|
1069
1067
|
|
|
1070
1068
|
def inspect
|
|
1071
|
-
inspect_orig.sub(/>$/, " @attribute
|
|
1069
|
+
inspect_orig.sub(/>$/, " @attribute=#{@attribute.to_s.sub(/>$/, " @name=#{@attribute.name}")}>")
|
|
1072
1070
|
end
|
|
1073
1071
|
end
|
|
1074
1072
|
|
|
@@ -1081,14 +1079,14 @@ module GoodData
|
|
|
1081
1079
|
if column then
|
|
1082
1080
|
super
|
|
1083
1081
|
else
|
|
1084
|
-
super({:type =>
|
|
1082
|
+
super({:type => 'anchor', :name => 'id'}, schema)
|
|
1085
1083
|
@labels = []
|
|
1086
1084
|
@primary_label = nil
|
|
1087
1085
|
end
|
|
1088
1086
|
end
|
|
1089
1087
|
|
|
1090
1088
|
def table
|
|
1091
|
-
@table ||=
|
|
1089
|
+
@table ||= 'f_' + @schema.name
|
|
1092
1090
|
end
|
|
1093
1091
|
|
|
1094
1092
|
def to_maql_create
|
|
@@ -1100,7 +1098,6 @@ module GoodData
|
|
|
1100
1098
|
end
|
|
1101
1099
|
maql
|
|
1102
1100
|
end
|
|
1103
|
-
|
|
1104
1101
|
end
|
|
1105
1102
|
|
|
1106
1103
|
##
|
|
@@ -1134,17 +1131,17 @@ module GoodData
|
|
|
1134
1131
|
|
|
1135
1132
|
def to_manifest_part(mode)
|
|
1136
1133
|
{
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1134
|
+
'populates' => [identifier],
|
|
1135
|
+
'mode' => mode,
|
|
1136
|
+
'columnName' => name
|
|
1140
1137
|
}
|
|
1141
1138
|
end
|
|
1142
1139
|
|
|
1143
1140
|
def to_wire_model
|
|
1144
1141
|
{
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1142
|
+
'fact' => {
|
|
1143
|
+
'identifier' => identifier,
|
|
1144
|
+
'title' => title
|
|
1148
1145
|
}
|
|
1149
1146
|
}
|
|
1150
1147
|
end
|
|
@@ -1154,7 +1151,6 @@ module GoodData
|
|
|
1154
1151
|
# Reference to another data set
|
|
1155
1152
|
#
|
|
1156
1153
|
class Reference < Column
|
|
1157
|
-
|
|
1158
1154
|
attr_accessor :reference, :schema_ref
|
|
1159
1155
|
|
|
1160
1156
|
def initialize(column, schema)
|
|
@@ -1193,10 +1189,10 @@ module GoodData
|
|
|
1193
1189
|
|
|
1194
1190
|
def to_manifest_part(mode)
|
|
1195
1191
|
{
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1192
|
+
'populates' => [label_column],
|
|
1193
|
+
'mode' => mode,
|
|
1194
|
+
'columnName' => name,
|
|
1195
|
+
'referenceKey' => 1
|
|
1200
1196
|
}
|
|
1201
1197
|
end
|
|
1202
1198
|
end
|
|
@@ -1205,14 +1201,13 @@ module GoodData
|
|
|
1205
1201
|
# Date as a reference to a date dimension
|
|
1206
1202
|
#
|
|
1207
1203
|
class DateReference < Reference
|
|
1208
|
-
|
|
1209
1204
|
attr_accessor :format, :output_format, :urn
|
|
1210
1205
|
|
|
1211
1206
|
def initialize(column, schema)
|
|
1212
1207
|
super column, schema
|
|
1213
|
-
@output_format = column[
|
|
1208
|
+
@output_format = column['format'] || 'dd/MM/yyyy'
|
|
1214
1209
|
@format = @output_format.gsub('yyyy', '%Y').gsub('MM', '%m').gsub('dd', '%d')
|
|
1215
|
-
@urn = column[:urn] ||
|
|
1210
|
+
@urn = column[:urn] || 'URN:GOODDATA:DATE'
|
|
1216
1211
|
end
|
|
1217
1212
|
|
|
1218
1213
|
def identifier
|
|
@@ -1221,11 +1216,11 @@ module GoodData
|
|
|
1221
1216
|
|
|
1222
1217
|
def to_manifest_part(mode)
|
|
1223
1218
|
{
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1219
|
+
'populates' => ["#{identifier}.#{DATE_ATTRIBUTE_DEFAULT_DISPLAY_FORM}"],
|
|
1220
|
+
'mode' => mode,
|
|
1221
|
+
'constraints' => {'date' => output_format},
|
|
1222
|
+
'columnName' => name,
|
|
1223
|
+
'referenceKey' => 1
|
|
1229
1224
|
}
|
|
1230
1225
|
end
|
|
1231
1226
|
|
|
@@ -1249,10 +1244,10 @@ module GoodData
|
|
|
1249
1244
|
|
|
1250
1245
|
def to_manifest_part(mode)
|
|
1251
1246
|
{
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1247
|
+
'populates' => ['label.stuff.mmddyy'],
|
|
1248
|
+
'format' => 'unknown',
|
|
1249
|
+
'mode' => mode,
|
|
1250
|
+
'referenceKey' => 1
|
|
1256
1251
|
}
|
|
1257
1252
|
end
|
|
1258
1253
|
end
|
|
@@ -1274,7 +1269,6 @@ module GoodData
|
|
|
1274
1269
|
# Time as a reference to a time-of-a-day dimension
|
|
1275
1270
|
#
|
|
1276
1271
|
class TimeReference < Reference
|
|
1277
|
-
|
|
1278
1272
|
end
|
|
1279
1273
|
|
|
1280
1274
|
##
|
|
@@ -1343,7 +1337,6 @@ module GoodData
|
|
|
1343
1337
|
def to_manifest_part(mode)
|
|
1344
1338
|
nil
|
|
1345
1339
|
end
|
|
1346
|
-
|
|
1347
1340
|
end
|
|
1348
1341
|
|
|
1349
1342
|
##
|
|
@@ -1351,8 +1344,10 @@ module GoodData
|
|
|
1351
1344
|
#
|
|
1352
1345
|
class Folder < MdObject
|
|
1353
1346
|
def initialize(title)
|
|
1347
|
+
# TODO: should a super be here?
|
|
1348
|
+
# how to deal with name vs title?
|
|
1354
1349
|
@title = title
|
|
1355
|
-
@name = title
|
|
1350
|
+
@name = GoodData::Helpers.sanitize_string(title)
|
|
1356
1351
|
end
|
|
1357
1352
|
|
|
1358
1353
|
def to_maql_create
|
|
@@ -1366,11 +1361,11 @@ module GoodData
|
|
|
1366
1361
|
#
|
|
1367
1362
|
class AttributeFolder < Folder
|
|
1368
1363
|
def type;
|
|
1369
|
-
|
|
1364
|
+
'ATTRIBUTE'
|
|
1370
1365
|
end
|
|
1371
1366
|
|
|
1372
1367
|
def type_prefix;
|
|
1373
|
-
|
|
1368
|
+
'dim'
|
|
1374
1369
|
end
|
|
1375
1370
|
end
|
|
1376
1371
|
|
|
@@ -1379,21 +1374,20 @@ module GoodData
|
|
|
1379
1374
|
#
|
|
1380
1375
|
class FactFolder < Folder
|
|
1381
1376
|
def type;
|
|
1382
|
-
|
|
1377
|
+
'FACT'
|
|
1383
1378
|
end
|
|
1384
1379
|
|
|
1385
1380
|
def type_prefix;
|
|
1386
|
-
|
|
1381
|
+
'ffld'
|
|
1387
1382
|
end
|
|
1388
1383
|
end
|
|
1389
1384
|
|
|
1390
1385
|
class DateDimension < MdObject
|
|
1391
|
-
|
|
1392
1386
|
def initialize(spec={})
|
|
1393
1387
|
super()
|
|
1394
1388
|
@name = spec[:name]
|
|
1395
1389
|
@title = spec[:title] || @name
|
|
1396
|
-
@urn = spec[:urn] ||
|
|
1390
|
+
@urn = spec[:urn] || 'URN:GOODDATA:DATE'
|
|
1397
1391
|
end
|
|
1398
1392
|
|
|
1399
1393
|
def to_maql_create
|
|
@@ -1401,12 +1395,10 @@ module GoodData
|
|
|
1401
1395
|
# title = "title"
|
|
1402
1396
|
# name = "name"
|
|
1403
1397
|
|
|
1404
|
-
maql =
|
|
1398
|
+
maql = ''
|
|
1405
1399
|
maql += "INCLUDE TEMPLATE \"#{@urn}\" MODIFY (IDENTIFIER \"#{@name}\", TITLE \"#{@title}\");"
|
|
1406
1400
|
maql
|
|
1407
1401
|
end
|
|
1408
|
-
|
|
1409
1402
|
end
|
|
1410
|
-
|
|
1411
1403
|
end
|
|
1412
1404
|
end
|