gooddata 0.6.0 → 0.6.2

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 (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