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.
Files changed (40) hide show
  1. data/Gemfile +2 -0
  2. data/bin/gooddata +291 -8
  3. data/gooddata.gemspec +14 -5
  4. data/lib/gooddata/client.rb +34 -5
  5. data/lib/gooddata/commands/api.rb +27 -30
  6. data/lib/gooddata/commands/process.rb +137 -0
  7. data/lib/gooddata/commands/profile.rb +5 -5
  8. data/lib/gooddata/commands/projects.rb +107 -40
  9. data/lib/gooddata/commands/runners.rb +37 -0
  10. data/lib/gooddata/commands/scaffold.rb +30 -0
  11. data/lib/gooddata/connection.rb +31 -19
  12. data/lib/gooddata/extract.rb +1 -1
  13. data/lib/gooddata/goodzilla/goodzilla.rb +40 -0
  14. data/lib/gooddata/model.rb +418 -138
  15. data/lib/gooddata/models/attribute.rb +24 -0
  16. data/lib/gooddata/models/dashboard.rb +60 -0
  17. data/lib/gooddata/models/data_result.rb +4 -6
  18. data/lib/gooddata/models/data_set.rb +20 -0
  19. data/lib/gooddata/models/display_form.rb +7 -0
  20. data/lib/gooddata/models/fact.rb +17 -0
  21. data/lib/gooddata/models/metadata.rb +69 -17
  22. data/lib/gooddata/models/metric.rb +90 -0
  23. data/lib/gooddata/models/process.rb +112 -0
  24. data/lib/gooddata/models/profile.rb +1 -1
  25. data/lib/gooddata/models/project.rb +85 -29
  26. data/lib/gooddata/models/report.rb +45 -0
  27. data/lib/gooddata/models/report_definition.rb +139 -0
  28. data/lib/gooddata/version.rb +1 -1
  29. data/lib/templates/bricks/brick.rb.erb +7 -0
  30. data/lib/templates/bricks/main.rb.erb +4 -0
  31. data/spec/goodzilla_spec.rb +57 -0
  32. data/spec/model_dsl_spec.rb +22 -0
  33. data/test/test_commands.rb +1 -1
  34. data/test/test_model.rb +6 -6
  35. metadata +137 -16
  36. data/bin/igd.rb +0 -33
  37. data/lib/gooddata/command.rb +0 -75
  38. data/lib/gooddata/commands/help.rb +0 -104
  39. data/lib/gooddata/commands/version.rb +0 -7
  40. data/test/helper.rb +0 -13
@@ -29,4 +29,4 @@ module GoodData
29
29
  @user = @json['accountSetting']['firstName'] + " " + @json['accountSetting']['lastName']
30
30
  end
31
31
  end
32
- end
32
+ end
@@ -1,4 +1,4 @@
1
- require 'zip/zip'
1
+ require 'zip'
2
2
  require 'fileutils'
3
3
 
4
4
  module GoodData
@@ -18,7 +18,7 @@ module GoodData
18
18
  def all
19
19
  json = GoodData.get GoodData.profile.projects
20
20
  json['projects'].map do |project|
21
- Project.new project['project']
21
+ Project.new project
22
22
  end
23
23
  end
24
24
 
@@ -29,6 +29,7 @@ module GoodData
29
29
  # - <id>
30
30
  #
31
31
  def [](id)
32
+ return id if id.respond_to?(:is_project?) && id.is_project?
32
33
  if id.to_s !~ /^(\/gdc\/(projects|md)\/)?[a-zA-Z\d]+$/
33
34
  raise ArgumentError.new("wrong type of argument. Should be either project ID or path")
34
35
  end
@@ -36,7 +37,7 @@ module GoodData
36
37
  id = id.match(/[a-zA-Z\d]+$/)[0] if id =~ /\//
37
38
 
38
39
  response = GoodData.get PROJECT_PATH % id
39
- Project.new response['project']
40
+ Project.new response
40
41
  end
41
42
 
42
43
  # Create a project from a given attributes
@@ -45,26 +46,32 @@ module GoodData
45
46
  # - :summary
46
47
  # - :template (default /projects/blank)
47
48
  #
48
- def create(attributes)
49
+ def create(attributes, &block)
49
50
  GoodData.logger.info "Creating project #{attributes[:title]}"
50
51
 
51
52
  auth_token = attributes.delete(:auth_token) || GoodData.connection.auth_token
52
53
 
53
- json = {
54
- 'meta' => {
55
- 'title' => attributes[:title],
56
- 'summary' => attributes[:summary]
57
- },
58
- 'content' => {
59
- # 'state' => 'ENABLED',
60
- 'guidedNavigation' => 1,
61
- 'authorizationToken' => auth_token
54
+ json = {:project =>
55
+ {
56
+ 'meta' => {
57
+ 'title' => attributes[:title],
58
+ 'summary' => attributes[:summary] || "No summary"
59
+ },
60
+ 'content' => {
61
+ 'guidedNavigation' => 1,
62
+ 'authorizationToken' => auth_token,
63
+ "driver" => "Pg"
64
+ }
62
65
  }
63
66
  }
64
-
65
67
  json['meta']['projectTemplate'] = attributes[:template] if attributes[:template] && !attributes[:template].empty?
66
68
  project = Project.new json
67
69
  project.save
70
+ if block
71
+ GoodData::with_project(project) do |p|
72
+ block.call(p)
73
+ end
74
+ end
68
75
  project
69
76
  end
70
77
  end
@@ -74,20 +81,29 @@ module GoodData
74
81
  end
75
82
 
76
83
  def save
77
- response = GoodData.post PROJECTS_PATH, { 'project' => @json }
84
+ response = GoodData.post PROJECTS_PATH, raw_data
78
85
  if uri == nil
79
86
  response = GoodData.get response['uri']
80
- @json = response['project']
87
+ @json = response
81
88
  end
82
89
  end
83
90
 
84
91
  def delete
85
92
  raise "Project '#{title}' with id #{uri} is already deleted" if state == :deleted
86
- GoodData.delete @json['links']['self']
93
+ GoodData.delete data['links']['self']
87
94
  end
88
95
 
89
96
  def uri
90
- @json['links']['self'] if @json['links'] && @json['links']['self']
97
+ data['links']['self'] if data && data['links'] && data['links']['self']
98
+ end
99
+
100
+ def browser_uri(options={})
101
+ ui = options[:ui]
102
+ if ui
103
+ GoodData.connection.url + "#s=" + uri
104
+ else
105
+ GoodData.connection.url + uri
106
+ end
91
107
  end
92
108
 
93
109
  def obj_id
@@ -95,15 +111,15 @@ module GoodData
95
111
  end
96
112
 
97
113
  def title
98
- @json['meta']['title'] if @json['meta']
114
+ data['meta']['title'] if data['meta']
99
115
  end
100
116
 
101
117
  def state
102
- @json['content']['state'].downcase.to_sym if @json['content'] && @json['content']['state']
118
+ data['content']['state'].downcase.to_sym if data['content'] && data['content']['state']
103
119
  end
104
120
 
105
121
  def md
106
- @md ||= Links.new GoodData.get(@json['links']['metadata'])
122
+ @md ||= Links.new GoodData.get(data['links']['metadata'])
107
123
  end
108
124
 
109
125
  # Creates a data set within the project
@@ -112,11 +128,38 @@ module GoodData
112
128
  # p.add_dataset 'Test', [ { 'name' => 'a1', 'type' => 'ATTRIBUTE' ... } ... ]
113
129
  # p.add_dataset 'title' => 'Test', 'columns' => [ { 'name' => 'a1', 'type' => 'ATTRIBUTE' ... } ... ]
114
130
  #
115
- def add_dataset(schema, columns = nil)
116
- schema = { 'title' => schema, 'columns' => columns } if columns
117
- schema = Model::Schema.new schema if schema.is_a? Hash
118
- raise ArgumentError.new("Required either schema object or title plus columns array") unless schema.is_a? Model::Schema
119
- Model.add_schema schema, self
131
+ def add_dataset(schema_def, columns = nil, &block)
132
+ schema = if block
133
+ builder = block.call(Model::SchemaBuilder.new(schema_def))
134
+ builder.to_schema
135
+ else
136
+ sch = { :title => schema_def, :columns => columns } if columns
137
+ sch = Model::Schema.new schema_def if schema_def.is_a? Hash
138
+ sch = schema_def if schema_def.is_a?(Model::Schema)
139
+ raise ArgumentError.new("Required either schema object or title plus columns array") unless schema_def.is_a? Model::Schema
140
+ sch
141
+ end
142
+ Model.add_schema(schema, self)
143
+ end
144
+
145
+ def add_metric(options={})
146
+ expression = options[:expression] || fail("Metric has to have its expression defined")
147
+ m1 = GoodData::Metric.create(options)
148
+ m1.save
149
+ end
150
+
151
+ def add_report(options={})
152
+ rep = GoodData::Report.create(options)
153
+ rep.save
154
+ end
155
+
156
+ def add_dashboard(options={})
157
+ dash = GoodData::Dashboard.create(options)
158
+ dash.save
159
+ end
160
+
161
+ def add_user(email_address, domain)
162
+
120
163
  end
121
164
 
122
165
  def upload(file, schema, mode = "FULL")
@@ -124,7 +167,7 @@ module GoodData
124
167
  end
125
168
 
126
169
  def slis
127
- link = "#{@json['links']['metadata']}#{SLIS_PATH}"
170
+ link = "#{data['links']['metadata']}#{SLIS_PATH}"
128
171
  Metadata.new GoodData.get(link)
129
172
  end
130
173
 
@@ -132,12 +175,25 @@ module GoodData
132
175
  datasets_uri = "#{md['data']}/sets"
133
176
  response = GoodData.get datasets_uri
134
177
  response['dataSetsInfo']['sets'].map do |ds|
135
- DataSet.new ds
178
+ DataSet[ds["meta"]["uri"]]
136
179
  end
137
180
  end
138
181
 
139
- def to_json
182
+ def raw_data
140
183
  @json
141
184
  end
185
+
186
+ def data
187
+ raw_data["project"]
188
+ end
189
+
190
+ def to_json
191
+ raw_data.to_json
192
+ end
193
+
194
+ def is_project?
195
+ true
196
+ end
197
+
142
198
  end
143
199
  end
@@ -1,6 +1,8 @@
1
1
  module GoodData
2
2
  class Report < GoodData::MdObject
3
3
 
4
+ root_key :report
5
+
4
6
  class << self
5
7
  def [](id)
6
8
  if id == :all
@@ -9,8 +11,51 @@ module GoodData
9
11
  super
10
12
  end
11
13
  end
14
+
15
+ def create(options={})
16
+ title = options[:title]
17
+ summary = options[:summary] || ""
18
+ rd = options[:rd] || ReportDefinition.create(:top => options[:top], :left => options[:left])
19
+ rd.save
20
+
21
+ report = Report.new({
22
+ "report" => {
23
+ "content" => {
24
+ "domains" => [],
25
+ "definitions" => [rd.uri]
26
+ },
27
+ "meta" => {
28
+ "tags" => "",
29
+ "deprecated" => "0",
30
+ "summary" => summary,
31
+ "title" => title
32
+ }
33
+ }
34
+ })
35
+ end
12
36
  end
13
37
 
38
+ # ----
39
+
40
+ def title=(a_title)
41
+ @json["report"]["meta"]["title"] = a_title
42
+ end
43
+
44
+ def summary=(a_summary)
45
+ @json[:report][:meta][:summary] = a_summary
46
+ end
47
+
48
+ def add_definition(a_definition)
49
+ @json[:report][:content][:definitions] << a_definition
50
+ end
51
+
52
+ def to_json(options={})
53
+ JSON.pretty_generate(@json, options)
54
+ end
55
+ # ----
56
+
57
+
58
+
14
59
  def results
15
60
  content["results"]
16
61
  end
@@ -0,0 +1,139 @@
1
+ module GoodData
2
+ class ReportDefinition < GoodData::MdObject
3
+
4
+ root_key :reportDefinition
5
+
6
+ class << self
7
+ def [](id)
8
+ if id == :all
9
+ GoodData.get(GoodData.project.md['query'] + '/reportdefinition/')['query']['entries']
10
+ else
11
+ super
12
+ end
13
+ end
14
+
15
+ def create_metrics_part(left, top)
16
+ stuff = Array(left) + Array(top)
17
+ stuff.find_all {|item| item.respond_to?(:is_metric?)}.map do |metric|
18
+ create_metric_part(metric)
19
+ end
20
+ end
21
+
22
+ def create_metric_part(metric)
23
+ {
24
+ "alias" => metric.title,
25
+ "uri" => metric.uri
26
+ }
27
+ end
28
+
29
+ def create_attribute_part(attrib)
30
+ {
31
+ "attribute" => {
32
+ "alias" => "",
33
+ "totals" => [],
34
+ "uri" => attrib.uri
35
+ }
36
+ }
37
+ end
38
+
39
+ def create_part(stuff)
40
+ stuff = Array(stuff)
41
+ parts = stuff.reduce([]) do |memo, item|
42
+ if item.respond_to?(:is_metric?)
43
+ memo
44
+ else
45
+ memo << create_attribute_part(item)
46
+ end
47
+ memo
48
+ end
49
+ if stuff.any? {|item| item.respond_to?(:is_metric?)}
50
+ parts << "metricGroup"
51
+ end
52
+ parts
53
+ end
54
+
55
+ def find(stuff)
56
+ stuff.map do |item|
57
+ if item.respond_to?(:is_attribute?)
58
+ item.display_forms.first
59
+ elsif item.is_a?(String)
60
+ GoodData::Attribute.find_first_by_title(item).display_forms.first
61
+ elsif item.is_a?(Hash) && item[:type].to_s == "metric"
62
+ GoodData::Metric.find_first_by_title(item[:title])
63
+ elsif item.is_a?(Hash) && item[:type].to_s == "attribute"
64
+ GoodData::Attribute.find_first_by_title(item[:title]).display_forms.first
65
+ else
66
+ item
67
+ end
68
+ end
69
+ end
70
+
71
+ def execute(options={})
72
+ left = Array(options[:left])
73
+ top = Array(options[:top])
74
+
75
+ metrics = (left + top).find_all {|item| item.respond_to?(:is_metric?)}
76
+
77
+ unsaved_metrics = metrics.reject {|i| i.saved?}
78
+ unsaved_metrics.each {|m| m.title = "Untitled metric" unless m.title}
79
+
80
+ begin
81
+ unsaved_metrics.each {|m| m.save}
82
+ rd = GoodData::ReportDefinition.create(options)
83
+ rd.save
84
+ rd.execute
85
+ ensure
86
+ rd.delete if rd.saved? rescue nil
87
+ unsaved_metrics.each {|m| m.delete if m.saved?}
88
+ end
89
+ end
90
+
91
+ def create(options={})
92
+ left = Array(options[:left])
93
+ top = Array(options[:top])
94
+
95
+ left = ReportDefinition.find(left)
96
+ top = ReportDefinition.find(top)
97
+
98
+ ReportDefinition.new({
99
+ "reportDefinition" => {
100
+ "content" => {
101
+ "grid" => {
102
+ "sort" => {
103
+ "columns" => [],
104
+ "rows" => []
105
+ },
106
+ "columnWidths" => [],
107
+ "columns" => ReportDefinition.create_part(top),
108
+ "metrics" => ReportDefinition.create_metrics_part(left, top),
109
+ "rows" => ReportDefinition.create_part(left),
110
+ },
111
+ "format" => "grid",
112
+ "filters" => []
113
+ },
114
+ "meta" => {
115
+ "tags" => "",
116
+ "summary" => "",
117
+ "title" => "Untitled report definition"
118
+ }
119
+ }
120
+ })
121
+ end
122
+ end
123
+
124
+ def metrics
125
+ content["grid"]["metrics"].map {|i| GoodData::Metric[i["uri"]]}
126
+ end
127
+
128
+ def execute
129
+ result = GoodData.post '/gdc/xtab2/executor3', {"report_req" => {"reportDefinition" => uri}}
130
+ data_result_uri = result["execResult"]["dataResult"]
131
+ result = GoodData.get data_result_uri
132
+ while result["taskState"] && result["taskState"]["status"] == "WAIT" do
133
+ sleep 10
134
+ result = GoodData.get data_result_uri
135
+ end
136
+ ReportDataResult.new(GoodData.get data_result_uri)
137
+ end
138
+ end
139
+ end
@@ -1,3 +1,3 @@
1
1
  module GoodData
2
- VERSION = "0.5.16"
2
+ VERSION = "0.6.0.pre2"
3
3
  end
@@ -0,0 +1,7 @@
1
+ class MyBrick < Gooddata::Bricks::Brick
2
+
3
+ def call(params)
4
+ # do something here
5
+ end
6
+
7
+ end
@@ -0,0 +1,4 @@
1
+ require 'gooddata/bricks'
2
+ require './mybrick'
3
+
4
+ Gooddata::Bricks::Pipeline.prepare([LoggerMiddleware, BenchMiddleware, GoodDataMiddleware, MyBrick])
@@ -0,0 +1,57 @@
1
+ require 'gooddata/goodzilla/goodzilla'
2
+
3
+ describe GoodData::SmallGoodZilla do
4
+
5
+ MAQL_EXAMPLE = 'SELECT SUM(#"Amount") WHERE @"Date"=#"X" AND ?"Snapshot EOP"=1'
6
+ FACTS = {
7
+ "Amount" => "a",
8
+ "X" => "x"
9
+ }
10
+ ATTRIBUTES = {
11
+ "Date" => "d"
12
+ }
13
+ METRICS = {
14
+ "Snapshot EOP" => "snap"
15
+ }
16
+ DICT = {
17
+ :facts => FACTS,
18
+ :attributes => ATTRIBUTES,
19
+ :metrics => METRICS,
20
+ }
21
+
22
+ it "should parse metrics out of the string" do
23
+ x = GoodData::SmallGoodZilla.get_facts(MAQL_EXAMPLE)
24
+ x.should == ["Amount", "X"]
25
+ end
26
+
27
+ it "should parse attributes out of the string" do
28
+ x = GoodData::SmallGoodZilla.get_attributes(MAQL_EXAMPLE)
29
+ x.should == ["Date"]
30
+ end
31
+
32
+ it "should parse metrics out of the string" do
33
+ x = GoodData::SmallGoodZilla.get_metrics(MAQL_EXAMPLE)
34
+ x.should == ["Snapshot EOP"]
35
+ end
36
+
37
+ it "should interpolate the values" do
38
+
39
+ interpolated = GoodData::SmallGoodZilla.interpolate({
40
+ :facts => ["Amount", "X"],
41
+ :attributes => ["Date"],
42
+ :metrics => ["Snapshot EOP"]
43
+ }, DICT)
44
+
45
+ interpolated.should == {
46
+ :facts => [["Amount", "a"], ["X", "x"]],
47
+ :attributes => [["Date", "d"]],
48
+ :metrics => [["Snapshot EOP", "snap"]]
49
+ }
50
+ end
51
+
52
+ it "should return interpolated metric" do
53
+ interpolated = GoodData::SmallGoodZilla.interpolate_metric(MAQL_EXAMPLE, DICT)
54
+ interpolated.should == "SELECT SUM([a]) WHERE [d]=[x] AND [snap]=1"
55
+ end
56
+
57
+ end