gooddata 0.6.0 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +13 -5
- data/.rubocop.yml +23 -0
- data/.travis.yml +9 -4
- data/CLI.md +439 -0
- data/Gemfile +0 -1
- data/README.md +2 -2
- data/Rakefile +60 -8
- data/doc/templates/default/module/setup.rb +1 -1
- data/examples.rb +2 -0
- data/gooddata +2 -0
- data/gooddata.gemspec +12 -8
- data/lib/gooddata.rb +0 -2
- data/lib/gooddata/bricks/base_downloader.rb +52 -47
- data/lib/gooddata/bricks/brick.rb +20 -31
- data/lib/gooddata/bricks/bricks.rb +1 -1
- data/lib/gooddata/bricks/middleware/base_middleware.rb +9 -7
- data/lib/gooddata/bricks/middleware/bench_middleware.rb +12 -10
- data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +28 -28
- data/lib/gooddata/bricks/middleware/fs_upload_middleware.rb +20 -16
- data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +21 -19
- data/lib/gooddata/bricks/middleware/logger_middleware.rb +10 -8
- data/lib/gooddata/bricks/middleware/restforce_middleware.rb +36 -34
- data/lib/gooddata/bricks/middleware/stdout_middleware.rb +11 -9
- data/lib/gooddata/bricks/middleware/twitter_middleware.rb +14 -12
- data/lib/gooddata/bricks/pipeline.rb +28 -0
- data/lib/gooddata/bricks/utils.rb +10 -8
- data/lib/gooddata/cli/cli.rb +1 -6
- data/lib/gooddata/cli/commands/auth_cmd.rb +1 -1
- data/lib/gooddata/cli/commands/console_cmd.rb +7 -5
- data/lib/gooddata/cli/commands/domain_cmd.rb +45 -0
- data/lib/gooddata/cli/commands/process_cmd.rb +42 -5
- data/lib/gooddata/cli/commands/project_cmd.rb +96 -36
- data/lib/gooddata/cli/commands/projects_cmd.rb +21 -0
- data/lib/gooddata/cli/commands/role_cmd.rb +28 -0
- data/lib/gooddata/cli/commands/run_ruby_cmd.rb +5 -5
- data/lib/gooddata/cli/commands/scaffold_cmd.rb +1 -1
- data/lib/gooddata/cli/commands/{profile_cmd.rb → user_cmd.rb} +7 -9
- data/lib/gooddata/cli/shared.rb +3 -2
- data/lib/gooddata/client.rb +16 -304
- data/lib/gooddata/commands/api.rb +13 -5
- data/lib/gooddata/commands/auth.rb +47 -40
- data/lib/gooddata/commands/base.rb +4 -2
- data/lib/gooddata/commands/commands.rb +1 -1
- data/lib/gooddata/commands/datasets.rb +20 -7
- data/lib/gooddata/commands/domain.rb +23 -0
- data/lib/gooddata/commands/process.rb +23 -117
- data/lib/gooddata/commands/project.rb +147 -0
- data/lib/gooddata/commands/projects.rb +8 -102
- data/lib/gooddata/commands/role.rb +26 -0
- data/lib/gooddata/commands/runners.rb +41 -38
- data/lib/gooddata/commands/scaffold.rb +46 -43
- data/lib/gooddata/commands/user.rb +33 -0
- data/lib/gooddata/connection.rb +43 -353
- data/lib/gooddata/core/connection.rb +389 -0
- data/lib/gooddata/core/core.rb +5 -4
- data/lib/gooddata/core/logging.rb +48 -0
- data/lib/gooddata/core/nil_logger.rb +13 -0
- data/lib/gooddata/core/project.rb +70 -0
- data/lib/gooddata/core/rest.rb +120 -0
- data/lib/gooddata/core/threaded.rb +14 -0
- data/lib/gooddata/core/user.rb +19 -0
- data/lib/gooddata/data/data.rb +2 -1
- data/lib/gooddata/data/guesser.rb +16 -12
- data/lib/gooddata/exceptions/command_failed.rb +1 -1
- data/lib/gooddata/exceptions/exceptions.rb +2 -1
- data/lib/gooddata/exceptions/no_project_error.rb +11 -0
- data/lib/gooddata/exceptions/project_not_found.rb +1 -1
- data/lib/gooddata/extensions/big_decimal.rb +6 -2
- data/lib/gooddata/extract.rb +10 -8
- data/lib/gooddata/goodzilla/goodzilla.rb +61 -59
- data/lib/gooddata/helpers.rb +15 -9
- data/lib/gooddata/models/account_settings.rb +124 -0
- data/lib/gooddata/models/attributes/anchor.rb +37 -0
- data/lib/gooddata/models/attributes/attributes.rb +8 -0
- data/lib/gooddata/models/attributes/date_attribute.rb +25 -0
- data/lib/gooddata/models/attributes/time_attribute.rb +24 -0
- data/lib/gooddata/models/columns/attribute.rb +71 -0
- data/lib/gooddata/models/columns/columns.rb +8 -0
- data/lib/gooddata/models/columns/date_column.rb +63 -0
- data/lib/gooddata/models/columns/fact_model.rb +54 -0
- data/lib/gooddata/models/columns/label.rb +55 -0
- data/lib/gooddata/models/columns/reference.rb +57 -0
- data/lib/gooddata/models/dashboard_builder.rb +26 -0
- data/lib/gooddata/models/data_result.rb +10 -9
- data/lib/gooddata/models/domain.rb +131 -0
- data/lib/gooddata/models/empty_result.rb +5 -8
- data/lib/gooddata/models/facts/facts.rb +8 -0
- data/lib/gooddata/models/facts/time_fact.rb +20 -0
- data/lib/gooddata/models/folders/attribute_folder.rb +20 -0
- data/lib/gooddata/models/folders/fact_folder.rb +20 -0
- data/lib/gooddata/models/folders/folders.rb +8 -0
- data/lib/gooddata/models/invitation.rb +78 -0
- data/lib/gooddata/models/links.rb +6 -6
- data/lib/gooddata/models/md_object.rb +25 -0
- data/lib/gooddata/models/metadata.rb +160 -62
- data/lib/gooddata/models/metadata/attribute.rb +81 -0
- data/lib/gooddata/models/metadata/column.rb +61 -0
- data/lib/gooddata/models/{dashboard.rb → metadata/dashboard.rb} +12 -7
- data/lib/gooddata/models/{data_set.rb → metadata/data_set.rb} +5 -4
- data/lib/gooddata/models/metadata/date_dimension.rb +26 -0
- data/lib/gooddata/models/metadata/display_form.rb +61 -0
- data/lib/gooddata/models/metadata/fact.rb +36 -0
- data/lib/gooddata/models/metadata/folder.rb +24 -0
- data/lib/gooddata/models/metadata/metadata.rb +8 -0
- data/lib/gooddata/models/metadata/metric.rb +197 -0
- data/lib/gooddata/models/metadata/report.rb +115 -0
- data/lib/gooddata/models/{report_definition.rb → metadata/report_definition.rb} +16 -10
- data/lib/gooddata/models/metadata/schema.rb +227 -0
- data/lib/gooddata/models/model.rb +38 -1339
- data/lib/gooddata/models/models.rb +5 -2
- data/lib/gooddata/models/module_constants.rb +29 -0
- data/lib/gooddata/models/process.rb +142 -13
- data/lib/gooddata/models/profile.rb +4 -6
- data/lib/gooddata/models/project.rb +406 -136
- data/lib/gooddata/models/project_blueprint.rb +221 -0
- data/lib/gooddata/models/project_builder.rb +136 -0
- data/lib/gooddata/models/project_creator.rb +138 -0
- data/lib/gooddata/models/project_metadata.rb +11 -10
- data/lib/gooddata/models/project_role.rb +92 -0
- data/lib/gooddata/models/references/date_reference.rb +44 -0
- data/lib/gooddata/models/references/references.rb +8 -0
- data/lib/gooddata/models/references/time_reference.rb +13 -0
- data/lib/gooddata/models/report_data_result.rb +11 -11
- data/lib/gooddata/models/schedule.rb +284 -0
- data/lib/gooddata/models/schema_blueprint.rb +158 -0
- data/lib/gooddata/models/schema_builder.rb +81 -0
- data/lib/gooddata/models/tab_builder.rb +23 -0
- data/lib/gooddata/models/user.rb +165 -0
- data/lib/gooddata/version.rb +1 -1
- data/lib/templates/project/data/devs.csv +1 -1
- data/lib/templates/project/data/repos.csv +1 -1
- data/lib/templates/project/model/model.rb.erb +7 -11
- data/spec/bricks/bricks_spec.rb +2 -0
- data/spec/data/test-ci-data.csv +2 -0
- data/spec/data/test_project_model_spec.json +7 -27
- data/spec/helpers/blueprint_helper.rb +2 -0
- data/spec/helpers/cli_helper.rb +2 -0
- data/spec/helpers/connection_helper.rb +14 -1
- data/spec/helpers/project_helper.rb +16 -0
- data/spec/helpers/schema_helper.rb +16 -0
- data/spec/integration/command_projects_spec.rb +7 -7
- data/spec/integration/create_from_template_spec.rb +2 -2
- data/spec/integration/full_project_spec.rb +160 -7
- data/spec/integration/partial_md_export_import_spec.rb +3 -3
- data/spec/logging_in_logging_out_spec.rb +2 -1
- data/spec/spec_helper.rb +26 -4
- data/spec/unit/bricks/bricks_spec.rb +15 -7
- data/spec/unit/bricks/middleware/bench_middleware_spec.rb +2 -0
- data/spec/unit/bricks/middleware/bulk_salesforce_middleware_spec.rb +2 -0
- data/spec/unit/bricks/middleware/gooddata_middleware_spec.rb +2 -0
- data/spec/unit/bricks/middleware/logger_middleware_spec.rb +2 -0
- data/spec/unit/bricks/middleware/restforce_middleware_spec.rb +2 -0
- data/spec/unit/bricks/middleware/stdout_middleware_spec.rb +2 -0
- data/spec/unit/bricks/middleware/twitter_middleware_spec.rb +2 -0
- data/spec/unit/cli/cli_spec.rb +2 -0
- data/spec/unit/cli/commands/cmd_api_spec.rb +23 -15
- data/spec/unit/cli/commands/cmd_auth_spec.rb +8 -4
- data/spec/unit/cli/commands/cmd_domain_spec.rb +82 -0
- data/spec/unit/cli/commands/cmd_process_spec.rb +29 -13
- data/spec/unit/cli/commands/cmd_project_spec.rb +51 -30
- data/spec/unit/cli/commands/cmd_role_spec.rb +44 -0
- data/spec/unit/cli/commands/cmd_run_ruby_spec.rb +8 -4
- data/spec/unit/cli/commands/cmd_scaffold_spec.rb +48 -11
- data/spec/unit/cli/commands/cmd_user_spec.rb +29 -0
- data/spec/unit/commands/command_api_spec.rb +1 -1
- data/spec/unit/commands/command_auth_spec.rb +100 -18
- data/spec/unit/commands/command_dataset_spec.rb +4 -0
- data/spec/unit/commands/command_process_spec.rb +9 -4
- data/spec/unit/commands/command_projects_spec.rb +10 -6
- data/spec/unit/commands/command_scaffold_spec.rb +5 -1
- data/spec/unit/commands/command_user_spec.rb +22 -0
- data/spec/unit/core/connection_spec.rb +35 -6
- data/spec/unit/core/logging_spec.rb +65 -0
- data/spec/unit/core/nil_logger_spec.rb +9 -0
- data/spec/unit/core/project_spec.rb +51 -0
- data/spec/unit/core/rest_spec.rb +33 -0
- data/spec/unit/data/guesser_spec.rb +5 -0
- data/spec/unit/godzilla/goodzilla_spec.rb +2 -0
- data/spec/unit/models/account_settings_spec.rb +28 -0
- data/spec/unit/models/anchor_spec.rb +32 -0
- data/spec/unit/models/attribute_column_spec.rb +7 -0
- data/spec/unit/models/domain_spec.rb +45 -0
- data/spec/unit/models/invitation_spec.rb +13 -0
- data/spec/unit/models/md_object_spec.rb +47 -0
- data/spec/unit/models/metric.rb +92 -0
- data/spec/unit/{model → models}/model_spec.rb +9 -7
- data/spec/unit/models/project_blueprint_spec.rb +202 -0
- data/spec/unit/models/project_creator.rb +73 -0
- data/spec/unit/models/project_role_spec.rb +90 -0
- data/spec/unit/models/project_spec.rb +143 -0
- data/spec/unit/models/schedule_spec.rb +491 -0
- data/spec/unit/{model → models}/schema_builder_spec.rb +2 -0
- data/spec/unit/{model → models}/tools_spec.rb +13 -7
- data/spec/unit/models/user_spec.rb +16 -0
- data/test/test_upload.rb +2 -0
- metadata +189 -86
- data/lib/gooddata/commands/profile.rb +0 -11
- data/lib/gooddata/models/attribute.rb +0 -29
- data/lib/gooddata/models/display_form.rb +0 -9
- data/lib/gooddata/models/fact.rb +0 -19
- data/lib/gooddata/models/metric.rb +0 -99
- data/lib/gooddata/models/report.rb +0 -89
- data/spec/data/blueprint_valid.json +0 -37
- data/spec/unit/cli/commands/cmd_profile_spec.rb +0 -16
- data/spec/unit/commands/command_profile_spec.rb +0 -18
- data/spec/unit/core/core_spec.rb +0 -7
- data/spec/unit/model/blueprint_spec.rb +0 -132
- 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
|
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)[
|
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
|
-
|
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,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
|