gooddata 0.6.0 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (208) hide show
  1. checksums.yaml +13 -5
  2. data/.rubocop.yml +23 -0
  3. data/.travis.yml +9 -4
  4. data/CLI.md +439 -0
  5. data/Gemfile +0 -1
  6. data/README.md +2 -2
  7. data/Rakefile +60 -8
  8. data/doc/templates/default/module/setup.rb +1 -1
  9. data/examples.rb +2 -0
  10. data/gooddata +2 -0
  11. data/gooddata.gemspec +12 -8
  12. data/lib/gooddata.rb +0 -2
  13. data/lib/gooddata/bricks/base_downloader.rb +52 -47
  14. data/lib/gooddata/bricks/brick.rb +20 -31
  15. data/lib/gooddata/bricks/bricks.rb +1 -1
  16. data/lib/gooddata/bricks/middleware/base_middleware.rb +9 -7
  17. data/lib/gooddata/bricks/middleware/bench_middleware.rb +12 -10
  18. data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +28 -28
  19. data/lib/gooddata/bricks/middleware/fs_upload_middleware.rb +20 -16
  20. data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +21 -19
  21. data/lib/gooddata/bricks/middleware/logger_middleware.rb +10 -8
  22. data/lib/gooddata/bricks/middleware/restforce_middleware.rb +36 -34
  23. data/lib/gooddata/bricks/middleware/stdout_middleware.rb +11 -9
  24. data/lib/gooddata/bricks/middleware/twitter_middleware.rb +14 -12
  25. data/lib/gooddata/bricks/pipeline.rb +28 -0
  26. data/lib/gooddata/bricks/utils.rb +10 -8
  27. data/lib/gooddata/cli/cli.rb +1 -6
  28. data/lib/gooddata/cli/commands/auth_cmd.rb +1 -1
  29. data/lib/gooddata/cli/commands/console_cmd.rb +7 -5
  30. data/lib/gooddata/cli/commands/domain_cmd.rb +45 -0
  31. data/lib/gooddata/cli/commands/process_cmd.rb +42 -5
  32. data/lib/gooddata/cli/commands/project_cmd.rb +96 -36
  33. data/lib/gooddata/cli/commands/projects_cmd.rb +21 -0
  34. data/lib/gooddata/cli/commands/role_cmd.rb +28 -0
  35. data/lib/gooddata/cli/commands/run_ruby_cmd.rb +5 -5
  36. data/lib/gooddata/cli/commands/scaffold_cmd.rb +1 -1
  37. data/lib/gooddata/cli/commands/{profile_cmd.rb → user_cmd.rb} +7 -9
  38. data/lib/gooddata/cli/shared.rb +3 -2
  39. data/lib/gooddata/client.rb +16 -304
  40. data/lib/gooddata/commands/api.rb +13 -5
  41. data/lib/gooddata/commands/auth.rb +47 -40
  42. data/lib/gooddata/commands/base.rb +4 -2
  43. data/lib/gooddata/commands/commands.rb +1 -1
  44. data/lib/gooddata/commands/datasets.rb +20 -7
  45. data/lib/gooddata/commands/domain.rb +23 -0
  46. data/lib/gooddata/commands/process.rb +23 -117
  47. data/lib/gooddata/commands/project.rb +147 -0
  48. data/lib/gooddata/commands/projects.rb +8 -102
  49. data/lib/gooddata/commands/role.rb +26 -0
  50. data/lib/gooddata/commands/runners.rb +41 -38
  51. data/lib/gooddata/commands/scaffold.rb +46 -43
  52. data/lib/gooddata/commands/user.rb +33 -0
  53. data/lib/gooddata/connection.rb +43 -353
  54. data/lib/gooddata/core/connection.rb +389 -0
  55. data/lib/gooddata/core/core.rb +5 -4
  56. data/lib/gooddata/core/logging.rb +48 -0
  57. data/lib/gooddata/core/nil_logger.rb +13 -0
  58. data/lib/gooddata/core/project.rb +70 -0
  59. data/lib/gooddata/core/rest.rb +120 -0
  60. data/lib/gooddata/core/threaded.rb +14 -0
  61. data/lib/gooddata/core/user.rb +19 -0
  62. data/lib/gooddata/data/data.rb +2 -1
  63. data/lib/gooddata/data/guesser.rb +16 -12
  64. data/lib/gooddata/exceptions/command_failed.rb +1 -1
  65. data/lib/gooddata/exceptions/exceptions.rb +2 -1
  66. data/lib/gooddata/exceptions/no_project_error.rb +11 -0
  67. data/lib/gooddata/exceptions/project_not_found.rb +1 -1
  68. data/lib/gooddata/extensions/big_decimal.rb +6 -2
  69. data/lib/gooddata/extract.rb +10 -8
  70. data/lib/gooddata/goodzilla/goodzilla.rb +61 -59
  71. data/lib/gooddata/helpers.rb +15 -9
  72. data/lib/gooddata/models/account_settings.rb +124 -0
  73. data/lib/gooddata/models/attributes/anchor.rb +37 -0
  74. data/lib/gooddata/models/attributes/attributes.rb +8 -0
  75. data/lib/gooddata/models/attributes/date_attribute.rb +25 -0
  76. data/lib/gooddata/models/attributes/time_attribute.rb +24 -0
  77. data/lib/gooddata/models/columns/attribute.rb +71 -0
  78. data/lib/gooddata/models/columns/columns.rb +8 -0
  79. data/lib/gooddata/models/columns/date_column.rb +63 -0
  80. data/lib/gooddata/models/columns/fact_model.rb +54 -0
  81. data/lib/gooddata/models/columns/label.rb +55 -0
  82. data/lib/gooddata/models/columns/reference.rb +57 -0
  83. data/lib/gooddata/models/dashboard_builder.rb +26 -0
  84. data/lib/gooddata/models/data_result.rb +10 -9
  85. data/lib/gooddata/models/domain.rb +131 -0
  86. data/lib/gooddata/models/empty_result.rb +5 -8
  87. data/lib/gooddata/models/facts/facts.rb +8 -0
  88. data/lib/gooddata/models/facts/time_fact.rb +20 -0
  89. data/lib/gooddata/models/folders/attribute_folder.rb +20 -0
  90. data/lib/gooddata/models/folders/fact_folder.rb +20 -0
  91. data/lib/gooddata/models/folders/folders.rb +8 -0
  92. data/lib/gooddata/models/invitation.rb +78 -0
  93. data/lib/gooddata/models/links.rb +6 -6
  94. data/lib/gooddata/models/md_object.rb +25 -0
  95. data/lib/gooddata/models/metadata.rb +160 -62
  96. data/lib/gooddata/models/metadata/attribute.rb +81 -0
  97. data/lib/gooddata/models/metadata/column.rb +61 -0
  98. data/lib/gooddata/models/{dashboard.rb → metadata/dashboard.rb} +12 -7
  99. data/lib/gooddata/models/{data_set.rb → metadata/data_set.rb} +5 -4
  100. data/lib/gooddata/models/metadata/date_dimension.rb +26 -0
  101. data/lib/gooddata/models/metadata/display_form.rb +61 -0
  102. data/lib/gooddata/models/metadata/fact.rb +36 -0
  103. data/lib/gooddata/models/metadata/folder.rb +24 -0
  104. data/lib/gooddata/models/metadata/metadata.rb +8 -0
  105. data/lib/gooddata/models/metadata/metric.rb +197 -0
  106. data/lib/gooddata/models/metadata/report.rb +115 -0
  107. data/lib/gooddata/models/{report_definition.rb → metadata/report_definition.rb} +16 -10
  108. data/lib/gooddata/models/metadata/schema.rb +227 -0
  109. data/lib/gooddata/models/model.rb +38 -1339
  110. data/lib/gooddata/models/models.rb +5 -2
  111. data/lib/gooddata/models/module_constants.rb +29 -0
  112. data/lib/gooddata/models/process.rb +142 -13
  113. data/lib/gooddata/models/profile.rb +4 -6
  114. data/lib/gooddata/models/project.rb +406 -136
  115. data/lib/gooddata/models/project_blueprint.rb +221 -0
  116. data/lib/gooddata/models/project_builder.rb +136 -0
  117. data/lib/gooddata/models/project_creator.rb +138 -0
  118. data/lib/gooddata/models/project_metadata.rb +11 -10
  119. data/lib/gooddata/models/project_role.rb +92 -0
  120. data/lib/gooddata/models/references/date_reference.rb +44 -0
  121. data/lib/gooddata/models/references/references.rb +8 -0
  122. data/lib/gooddata/models/references/time_reference.rb +13 -0
  123. data/lib/gooddata/models/report_data_result.rb +11 -11
  124. data/lib/gooddata/models/schedule.rb +284 -0
  125. data/lib/gooddata/models/schema_blueprint.rb +158 -0
  126. data/lib/gooddata/models/schema_builder.rb +81 -0
  127. data/lib/gooddata/models/tab_builder.rb +23 -0
  128. data/lib/gooddata/models/user.rb +165 -0
  129. data/lib/gooddata/version.rb +1 -1
  130. data/lib/templates/project/data/devs.csv +1 -1
  131. data/lib/templates/project/data/repos.csv +1 -1
  132. data/lib/templates/project/model/model.rb.erb +7 -11
  133. data/spec/bricks/bricks_spec.rb +2 -0
  134. data/spec/data/test-ci-data.csv +2 -0
  135. data/spec/data/test_project_model_spec.json +7 -27
  136. data/spec/helpers/blueprint_helper.rb +2 -0
  137. data/spec/helpers/cli_helper.rb +2 -0
  138. data/spec/helpers/connection_helper.rb +14 -1
  139. data/spec/helpers/project_helper.rb +16 -0
  140. data/spec/helpers/schema_helper.rb +16 -0
  141. data/spec/integration/command_projects_spec.rb +7 -7
  142. data/spec/integration/create_from_template_spec.rb +2 -2
  143. data/spec/integration/full_project_spec.rb +160 -7
  144. data/spec/integration/partial_md_export_import_spec.rb +3 -3
  145. data/spec/logging_in_logging_out_spec.rb +2 -1
  146. data/spec/spec_helper.rb +26 -4
  147. data/spec/unit/bricks/bricks_spec.rb +15 -7
  148. data/spec/unit/bricks/middleware/bench_middleware_spec.rb +2 -0
  149. data/spec/unit/bricks/middleware/bulk_salesforce_middleware_spec.rb +2 -0
  150. data/spec/unit/bricks/middleware/gooddata_middleware_spec.rb +2 -0
  151. data/spec/unit/bricks/middleware/logger_middleware_spec.rb +2 -0
  152. data/spec/unit/bricks/middleware/restforce_middleware_spec.rb +2 -0
  153. data/spec/unit/bricks/middleware/stdout_middleware_spec.rb +2 -0
  154. data/spec/unit/bricks/middleware/twitter_middleware_spec.rb +2 -0
  155. data/spec/unit/cli/cli_spec.rb +2 -0
  156. data/spec/unit/cli/commands/cmd_api_spec.rb +23 -15
  157. data/spec/unit/cli/commands/cmd_auth_spec.rb +8 -4
  158. data/spec/unit/cli/commands/cmd_domain_spec.rb +82 -0
  159. data/spec/unit/cli/commands/cmd_process_spec.rb +29 -13
  160. data/spec/unit/cli/commands/cmd_project_spec.rb +51 -30
  161. data/spec/unit/cli/commands/cmd_role_spec.rb +44 -0
  162. data/spec/unit/cli/commands/cmd_run_ruby_spec.rb +8 -4
  163. data/spec/unit/cli/commands/cmd_scaffold_spec.rb +48 -11
  164. data/spec/unit/cli/commands/cmd_user_spec.rb +29 -0
  165. data/spec/unit/commands/command_api_spec.rb +1 -1
  166. data/spec/unit/commands/command_auth_spec.rb +100 -18
  167. data/spec/unit/commands/command_dataset_spec.rb +4 -0
  168. data/spec/unit/commands/command_process_spec.rb +9 -4
  169. data/spec/unit/commands/command_projects_spec.rb +10 -6
  170. data/spec/unit/commands/command_scaffold_spec.rb +5 -1
  171. data/spec/unit/commands/command_user_spec.rb +22 -0
  172. data/spec/unit/core/connection_spec.rb +35 -6
  173. data/spec/unit/core/logging_spec.rb +65 -0
  174. data/spec/unit/core/nil_logger_spec.rb +9 -0
  175. data/spec/unit/core/project_spec.rb +51 -0
  176. data/spec/unit/core/rest_spec.rb +33 -0
  177. data/spec/unit/data/guesser_spec.rb +5 -0
  178. data/spec/unit/godzilla/goodzilla_spec.rb +2 -0
  179. data/spec/unit/models/account_settings_spec.rb +28 -0
  180. data/spec/unit/models/anchor_spec.rb +32 -0
  181. data/spec/unit/models/attribute_column_spec.rb +7 -0
  182. data/spec/unit/models/domain_spec.rb +45 -0
  183. data/spec/unit/models/invitation_spec.rb +13 -0
  184. data/spec/unit/models/md_object_spec.rb +47 -0
  185. data/spec/unit/models/metric.rb +92 -0
  186. data/spec/unit/{model → models}/model_spec.rb +9 -7
  187. data/spec/unit/models/project_blueprint_spec.rb +202 -0
  188. data/spec/unit/models/project_creator.rb +73 -0
  189. data/spec/unit/models/project_role_spec.rb +90 -0
  190. data/spec/unit/models/project_spec.rb +143 -0
  191. data/spec/unit/models/schedule_spec.rb +491 -0
  192. data/spec/unit/{model → models}/schema_builder_spec.rb +2 -0
  193. data/spec/unit/{model → models}/tools_spec.rb +13 -7
  194. data/spec/unit/models/user_spec.rb +16 -0
  195. data/test/test_upload.rb +2 -0
  196. metadata +189 -86
  197. data/lib/gooddata/commands/profile.rb +0 -11
  198. data/lib/gooddata/models/attribute.rb +0 -29
  199. data/lib/gooddata/models/display_form.rb +0 -9
  200. data/lib/gooddata/models/fact.rb +0 -19
  201. data/lib/gooddata/models/metric.rb +0 -99
  202. data/lib/gooddata/models/report.rb +0 -89
  203. data/spec/data/blueprint_valid.json +0 -37
  204. data/spec/unit/cli/commands/cmd_profile_spec.rb +0 -16
  205. data/spec/unit/commands/command_profile_spec.rb +0 -18
  206. data/spec/unit/core/core_spec.rb +0 -7
  207. data/spec/unit/model/blueprint_spec.rb +0 -132
  208. data/spec/unit/model/project_blueprint_spec.rb +0 -44
@@ -0,0 +1,61 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative '../md_object'
4
+ require_relative '../../helpers'
5
+
6
+ module GoodData
7
+ module Model
8
+ ##
9
+ # This is a base class for server-side LDM elements such as attributes, labels and
10
+ # facts
11
+ #
12
+ class Column < MdObject
13
+ attr_accessor :folder, :name, :title, :schema
14
+
15
+ def initialize(hash, schema)
16
+ super()
17
+ fail(ArgumentError, "Schema must be provided, got #{schema.class}") unless schema.is_a? Schema
18
+ fail('Data set fields must have their names defined') if hash[:name].nil?
19
+
20
+ @name = hash[:name]
21
+ @title = hash[:title] || hash[:name].humanize
22
+ @folder = hash[:folder]
23
+ @schema = schema
24
+ end
25
+
26
+ ##
27
+ # Generates an identifier from the object name by transliterating
28
+ # non-Latin character and then dropping non-alphanumerical characters.
29
+ #
30
+ def identifier
31
+ @identifier ||= "#{type_prefix}.#{@schema.name}.#{name}"
32
+ end
33
+
34
+ def to_maql_drop
35
+ "DROP {#{identifier}};\n"
36
+ end
37
+
38
+ def visual
39
+ visual = super
40
+ visual += ", FOLDER {#{folder_prefix}.#{(folder)}}" if folder
41
+ visual
42
+ end
43
+
44
+ def to_csv_header(row)
45
+ name
46
+ end
47
+
48
+ def to_csv_data(headers, row)
49
+ row[name]
50
+ end
51
+
52
+ # Overriden to prevent long strings caused by the @schema attribute
53
+ #
54
+ def inspect
55
+ to_s.sub(/>$/, " @title=#{@title.inspect}, @name=#{@name.inspect}, @folder=#{@folder.inspect}," \
56
+ " @schema=#{@schema.to_s.sub(/>$/, ' @title=' + @schema.name.inspect + '>')}" \
57
+ ">")
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,13 +1,18 @@
1
1
  # encoding: UTF-8
2
2
 
3
+ require_relative '../../core/core'
4
+ require_relative '../metadata'
3
5
  require_relative 'metadata'
6
+ require_relative 'report'
7
+
8
+ require 'multi_json'
4
9
 
5
10
  module GoodData
6
11
  class Dashboard < GoodData::MdObject
7
12
  root_key :projectDashboard
8
13
 
9
14
  class << self
10
- def [](id)
15
+ def [](id, options = {})
11
16
  if id == :all
12
17
  GoodData.get(GoodData.project.md['query'] + '/projectdashboards/')['query']['entries']
13
18
  else
@@ -23,7 +28,7 @@ module GoodData
23
28
  }
24
29
  end
25
30
 
26
- def create_report_tab_item(options={})
31
+ def create_report_tab_item(options = {})
27
32
  title = options[:title]
28
33
 
29
34
  report = GoodData::Report.find_first_by_title(title)
@@ -53,7 +58,7 @@ module GoodData
53
58
  }
54
59
  end
55
60
 
56
- def create(options={})
61
+ def create(options = {})
57
62
  stuff = {
58
63
  'projectDashboard' => {
59
64
  'content' => {
@@ -75,16 +80,16 @@ module GoodData
75
80
  true
76
81
  end
77
82
 
78
- def export(format, options={})
83
+ def export(format, options = {})
79
84
  supported_formats = [:pdf]
80
85
  fail "Wrong format provied \"#{format}\". Only supports formats #{supported_formats.join(', ')}" unless supported_formats.include?(format)
81
86
  tab = options[:tab] || ''
82
87
 
83
88
  req_uri = "/gdc/projects/#{GoodData.project.uri}/clientexport"
84
- x = GoodData.post(req_uri, {'clientExport' => {'url' => "https://secure.gooddata.com/dashboard.html#project=#{GoodData.project.uri}&dashboard=#{uri}&tab=#{tab}&export=1", 'name' => title}}, :process => false)
85
- while (x.code == 202) do
89
+ x = GoodData.post(req_uri, { 'clientExport' => { 'url' => "https://secure.gooddata.com/dashboard.html#project=#{GoodData.project.uri}&dashboard=#{uri}&tab=#{tab}&export=1", 'name' => title } }, :process => false)
90
+ while x.code == 202
86
91
  sleep(1)
87
- uri = MultiJson.load(x.body)["asyncTask"]["link"]["poll"]
92
+ uri = MultiJson.load(x.body)['asyncTask']['link']['poll']
88
93
  x = GoodData.get(uri, :process => false)
89
94
  end
90
95
  x
@@ -1,9 +1,10 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require_relative 'metadata.rb'
3
+ require_relative '../metadata.rb'
4
+ require_relative 'metadata'
4
5
 
5
6
  module GoodData
6
- class DataSet < MdObject
7
+ class DataSet < GoodData::MdObject
7
8
  root_key :dataSet
8
9
 
9
10
  SLI_CTG = 'singleloadinterface'
@@ -14,7 +15,7 @@ module GoodData
14
15
  end
15
16
 
16
17
  def sli
17
- raise NoProjectError.new 'Connect to a project before searching for an object' unless GoodData.project
18
+ fail(NoProjectError, 'Connect to a project before searching for an object') unless GoodData.project
18
19
  slis = GoodData.project.md.links(Model::LDM_CTG).links(SLI_CTG)[DS_SLI_CTG]
19
20
  uri = slis[identifier]['link']
20
21
  MdObject[uri]
@@ -28,4 +29,4 @@ module GoodData
28
29
  content['facts'].map { |a| GoodData::Attribute[a] }
29
30
  end
30
31
  end
31
- end
32
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative '../md_object'
4
+
5
+ module GoodData
6
+ module Model
7
+ class DateDimension < MdObject
8
+ def initialize(spec = {})
9
+ super()
10
+ @name = spec[:name]
11
+ @title = spec[:title] || @name
12
+ @urn = spec[:urn] || 'URN:GOODDATA:DATE'
13
+ end
14
+
15
+ def to_maql_create
16
+ # urn = "urn:chefs_warehouse_fiscal:date"
17
+ # title = "title"
18
+ # name = "name"
19
+
20
+ maql = ''
21
+ maql += "INCLUDE TEMPLATE \"#{@urn}\" MODIFY (IDENTIFIER \"#{@name}\", TITLE \"#{@title}\");"
22
+ maql
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,61 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative '../metadata'
4
+ require_relative 'metadata'
5
+
6
+ module GoodData
7
+ class DisplayForm < GoodData::MdObject
8
+ root_key :attributeDisplayForm
9
+
10
+ # Finds an attribute element URI for given value. This URI can be used by find_element_value to find the original value again
11
+ # @param [String] value value of an label you are looking for
12
+ # @return [String]
13
+ def find_value_uri(value)
14
+ value = CGI.escapeHTML(value)
15
+ results = GoodData.post("#{uri}/validElements?limit=30&offset=0&order=asc&filter=#{value}", {})
16
+ items = results['validElements']['items']
17
+ if items.empty?
18
+ fail "#{value} not found"
19
+ else
20
+ items.first['element']['uri']
21
+ end
22
+ end
23
+
24
+ # For an element id find values (titles) for this label. Element id can be given as both number id or URI as a string beginning with /
25
+ # @param [Object] element_id Element identifier either Number or a uri as a String
26
+ # @return [String] value of the element if found
27
+ def find_element_value(element_id)
28
+ element_id = element_id.is_a?(String) ? element_id.match(/\?id=(\d)/)[1] : element_id
29
+ uri = links['elements']
30
+ result = GoodData.get(uri + "/?id=#{element_id}")
31
+ items = result['attributeElements']['elements']
32
+ if items.empty?
33
+ fail "Element id #{element_id} was not found"
34
+ else
35
+ items.first['title']
36
+ end
37
+ end
38
+
39
+ # Returns all values for this label. This is for inspection purposes only since obviously there can be huge number of elements.
40
+ # @param [Hash] options the options to pass to the value list
41
+ # @option options [Number] :limit limits the number of values to certain number. Default is 100
42
+ # @return [Array]
43
+ def values(options = {})
44
+ limit = options[:limit] || 100
45
+ results = GoodData.post("#{uri}/validElements?limit=#{limit}&offset=0&order=asc", {})
46
+ results['validElements']['items'].map do |el|
47
+ v = el['element']
48
+ {
49
+ :value => v['title'],
50
+ :uri => v['uri']
51
+ }
52
+ end
53
+ end
54
+
55
+ # Gives an attribute of current label
56
+ # @return [GoodData::Attibute]
57
+ def attribute
58
+ GoodData::Attribute[content['formOf']]
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative '../metadata'
4
+ require_relative '../../core/rest'
5
+ require_relative 'metadata'
6
+
7
+ module GoodData
8
+ class Fact < GoodData::MdObject
9
+ root_key :fact
10
+
11
+ # TODO: verify that we have all (which we do not right now)
12
+ FACT_BASE_AGGREGATIONS = [:sum, :min, :max, :avg, :median]
13
+
14
+ class << self
15
+ def [](id, options = {})
16
+ if id == :all
17
+ facts = GoodData.get(GoodData.project.md['query'] + '/facts/')['query']['entries']
18
+ options[:full] ? facts.map { |f| Fact[f['link']] } : facts
19
+ else
20
+ super
21
+ end
22
+ end
23
+ end
24
+
25
+ def fact?
26
+ true
27
+ end
28
+
29
+ def create_metric(options = {})
30
+ a_type = options[:type] || :sum
31
+ fail "Suggested aggreagtion function (#{a_type}) does not exist for base metric created out of fact. You can use only one of #{FACT_BASE_AGGREGATIONS.map { |x| ":" + x.to_s }.join(',')}" unless FACT_BASE_AGGREGATIONS.include?(a_type)
32
+ a_title = options[:title] || "#{a_type} of #{title}"
33
+ Metric.xcreate(:expression => "SELECT #{a_type.to_s.upcase}(![#{identifier}])", :title => a_title)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative '../md_object'
4
+
5
+ module GoodData
6
+ module Model
7
+ ##
8
+ # Base class for GoodData attribute and fact folder abstractions
9
+ #
10
+ class Folder < MdObject
11
+ def initialize(title)
12
+ # TODO: should a super be here?
13
+ # how to deal with name vs title?
14
+ @title = title
15
+ @name = GoodData::Helpers.sanitize_string(title)
16
+ end
17
+
18
+ def to_maql_create
19
+ "CREATE FOLDER {#{type_prefix}.#{name}}" \
20
+ + " VISUAL (#{visual}) TYPE #{type};\n"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'pathname'
4
+
5
+ base = Pathname(__FILE__).dirname.expand_path
6
+ Dir.glob(base + '*.rb').each do |file|
7
+ require file
8
+ end
@@ -0,0 +1,197 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative '../../goodzilla/goodzilla'
4
+ require_relative '../metadata'
5
+ require_relative 'metadata'
6
+
7
+ module GoodData
8
+ # Metric representation
9
+ class Metric < MdObject
10
+ root_key :metric
11
+
12
+ PARSE_MAQL_OBJECT_REGEXP = /\[([^\]]+)\]/
13
+
14
+ class << self
15
+ def [](id, options = {})
16
+ if id == :all
17
+ metrics = GoodData.get(GoodData.project.md['query'] + '/metrics/')['query']['entries']
18
+ options[:full] ? metrics.map { |m| Metric[m['link']] } : metrics
19
+ else
20
+ super
21
+ end
22
+ end
23
+
24
+ def xcreate(options)
25
+ if options.is_a?(String)
26
+ create(:expression => options, :extended_notation => true)
27
+ else
28
+ create(options.merge(:extended_notation => true))
29
+ end
30
+ end
31
+
32
+ def create(options = {})
33
+ if options.is_a?(String)
34
+ expression = options
35
+ extended_notation = false
36
+ title = nil
37
+ else
38
+ title = options[:title]
39
+ summary = options[:summary]
40
+ expression = options[:expression] || fail('Metric has to have its expression defined')
41
+ extended_notation = options[:extended_notation] || false
42
+ end
43
+
44
+ expression = if extended_notation
45
+ dict = {
46
+ :facts => GoodData::Fact[:all].reduce({}) do |memo, item|
47
+ memo[item['title']] = item['link']
48
+ memo
49
+ end,
50
+ :attributes => GoodData::Attribute[:all].reduce({}) do |memo, item|
51
+ memo[item['title']] = item['link']
52
+ memo
53
+ end,
54
+ :metrics => GoodData::Metric[:all].reduce({}) do |memo, item|
55
+ memo[item['title']] = item['link']
56
+ memo
57
+ end
58
+ }
59
+ interpolated_metric = GoodData::SmallGoodZilla.interpolate_metric(expression, dict)
60
+ interpolated_metric
61
+ else
62
+ expression
63
+ end
64
+
65
+ metric = {
66
+ 'metric' => {
67
+ 'content' => {
68
+ 'format' => '#,##0',
69
+ 'expression' => expression
70
+ },
71
+ 'meta' => {
72
+ 'tags' => '',
73
+ 'summary' => summary,
74
+ 'title' => title
75
+ }
76
+ }
77
+ }
78
+ # TODO: add test for explicitly provided identifier
79
+ metric['metric']['meta']['identifier'] = options[:identifier] if options[:identifier]
80
+ Metric.new(metric)
81
+ end
82
+
83
+ def execute(expression, options = {})
84
+ m = if expression.is_a?(String)
85
+ tmp = {
86
+ :title => 'Temporary metric to be deleted',
87
+ :expression => expression
88
+ }.merge(options)
89
+
90
+ GoodData::Metric.create(tmp)
91
+ else
92
+ tmp = {
93
+ :title => 'Temporary metric to be deleted'
94
+ }.merge(expression)
95
+ GoodData::Metric.create(tmp)
96
+ end
97
+ m.execute
98
+ end
99
+
100
+ def xexecute(expression)
101
+ if expression.is_a?(String)
102
+ execute(:expression => expression, :extended_notation => true)
103
+ else
104
+ execute(expression.merge(:extended_notation => true))
105
+ end
106
+ end
107
+ end
108
+
109
+ def execute
110
+ res = GoodData::ReportDefinition.execute(:left => self)
111
+ res[0][0]
112
+ end
113
+
114
+ def expression
115
+ content['expression']
116
+ end
117
+
118
+ def expression=(value)
119
+ content['expression'] = value
120
+ end
121
+
122
+ def validate
123
+ fail 'Meric needs to have title' if title.nil?
124
+ true
125
+ end
126
+
127
+ def metric?
128
+ true
129
+ end
130
+
131
+ # Checks that the expression contains certain metadata object. The difference between this and used_by using is in the fact that this is not a transitive closure. it searches only inside the expression
132
+ # @param [GoodData::MdObject] item Object that is going to be looked up
133
+ # @return [Boolean]
134
+ def contain?(item)
135
+ uri = item.respond_to?(:uri) ? item.uri : item
136
+ expression[uri] != nil
137
+ end
138
+
139
+ # Checks that the expression contains certain element of an attribute. The value is looked up through given label.
140
+ # @param [GoodData::DisplayForm] label Label though which the value is looked up
141
+ # @param [String] value Value that will be looked up through the label.
142
+ # @return [Boolean]
143
+ def contain_value?(label, value)
144
+ uri = label.find_value_uri(value)
145
+ contain?(uri)
146
+ end
147
+
148
+ # Method used for replacing objects like Attribute, Fact or Metric.
149
+ # @param [GoodData::MdObject] what Object that should be replaced
150
+ # @param [GoodData::MdObject] for_what Object it is replaced with
151
+ # @return [GoodData::Metric]
152
+ def replace(what, for_what)
153
+ uri_what = what.respond_to?(:uri) ? what.uri : what
154
+ uri_for_what = for_what.respond_to?(:uri) ? for_what.uri : for_what
155
+ self.expression = expression.gsub(uri_what, uri_for_what)
156
+ self
157
+ end
158
+
159
+ # Method used for replacing attribute element values. Looks up certain value of a label in the MAQL expression and exchanges it for a different value of the same label.
160
+ # @param [GoodData::DisplayForm] label Label through which the value and for_value are resolved
161
+ # @param [String] value value that is going to be replaced
162
+ # @param [String] for_value value that is going to be the new one
163
+ # @return [GoodData::Metric]
164
+ def replace_value(label, value, for_label, for_value = nil)
165
+ label = label.respond_to?(:primary_label) ? label.primary_label : label
166
+ if for_value
167
+ for_label = for_label.respond_to?(:primary_label) ? for_label.primary_label : for_label
168
+ value_uri = label.find_value_uri(value)
169
+ for_value_uri = for_label.find_value_uri(for_value)
170
+ self.expression = expression.gsub(value_uri, for_value_uri)
171
+ self.expression = expression.gsub(label.attribute.uri, for_label.attribute.uri)
172
+ else
173
+ for_value = for_label
174
+ value_uri = label.find_value_uri(value)
175
+ for_value_uri = label.find_value_uri(for_value)
176
+ self.expression = expression.gsub(value_uri, for_value_uri)
177
+ end
178
+ self
179
+ end
180
+
181
+ # Looks up the readable values of the objects used inside of MAQL epxpressions. Labels and elements titles are based on the primary label.
182
+ # @return [String] Ther resulting MAQL like expression
183
+ def pretty_expression
184
+ temp = expression.dup
185
+ expression.scan(PARSE_MAQL_OBJECT_REGEXP).each do |uri|
186
+ uri = uri.first
187
+ if uri =~ /elements/
188
+ temp.sub!(uri, Attribute.find_element_value(uri))
189
+ else
190
+ obj = GoodData::MdObject[uri]
191
+ temp.sub!(uri, obj.title)
192
+ end
193
+ end
194
+ temp
195
+ end
196
+ end
197
+ end