gooddata 0.5.16 → 0.6.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
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