gooddata 0.6.4 → 0.6.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +4 -0
- data/README.md +1 -0
- data/lib/gooddata/cli/commands/project_cmd.rb +2 -7
- data/lib/gooddata/client.rb +0 -2
- data/lib/gooddata/commands/project.rb +10 -0
- data/lib/gooddata/core/rest.rb +12 -2
- data/lib/gooddata/exceptions/attr_element_not_found.rb +12 -0
- data/lib/gooddata/extensions/enumerable.rb +12 -0
- data/lib/gooddata/helpers/global_helpers.rb +20 -0
- data/lib/gooddata/mixins/author.rb +16 -0
- data/lib/gooddata/mixins/content_getter.rb +11 -0
- data/lib/gooddata/mixins/content_property_reader.rb +13 -0
- data/lib/gooddata/mixins/content_property_writer.rb +13 -0
- data/lib/gooddata/mixins/contributor.rb +16 -0
- data/lib/gooddata/mixins/data_getter.rb +11 -0
- data/lib/gooddata/mixins/data_property_reader.rb +13 -0
- data/lib/gooddata/mixins/data_property_writer.rb +13 -0
- data/lib/gooddata/mixins/is_attribute.rb +13 -0
- data/lib/gooddata/mixins/is_fact.rb +13 -0
- data/lib/gooddata/mixins/is_label.rb +15 -0
- data/lib/gooddata/mixins/links.rb +11 -0
- data/lib/gooddata/mixins/md_finders.rb +36 -0
- data/lib/gooddata/mixins/md_id_to_uri.rb +29 -0
- data/lib/gooddata/mixins/md_json.rb +11 -0
- data/lib/gooddata/mixins/md_object_id.rb +11 -0
- data/lib/gooddata/mixins/md_object_indexer.rb +36 -0
- data/lib/gooddata/mixins/md_object_query.rb +83 -0
- data/lib/gooddata/mixins/md_relations.rb +39 -0
- data/lib/gooddata/mixins/meta_getter.rb +11 -0
- data/lib/gooddata/mixins/meta_property_reader.rb +13 -0
- data/lib/gooddata/mixins/meta_property_writer.rb +13 -0
- data/lib/gooddata/mixins/mixins.rb +15 -0
- data/lib/gooddata/mixins/not_attribute.rb +13 -0
- data/lib/gooddata/mixins/not_exportable.rb +11 -0
- data/lib/gooddata/mixins/not_fact.rb +13 -0
- data/lib/gooddata/mixins/not_label.rb +15 -0
- data/lib/gooddata/mixins/not_metric.rb +13 -0
- data/lib/gooddata/mixins/obj_id.rb +11 -0
- data/lib/gooddata/mixins/rest_getters.rb +13 -0
- data/lib/gooddata/mixins/rest_resource.rb +19 -0
- data/lib/gooddata/mixins/root_key_getter.rb +11 -0
- data/lib/gooddata/mixins/root_key_setter.rb +11 -0
- data/lib/gooddata/mixins/timestamps.rb +15 -0
- data/lib/gooddata/models/from_wire.rb +153 -0
- data/lib/gooddata/models/metadata.rb +28 -230
- data/lib/gooddata/models/metadata/attribute.rb +4 -6
- data/lib/gooddata/models/metadata/fact.rb +4 -6
- data/lib/gooddata/models/metadata/{display_form.rb → label.rb} +17 -11
- data/lib/gooddata/models/metadata/metric.rb +1 -1
- data/lib/gooddata/models/metadata/report_definition.rb +2 -2
- data/lib/gooddata/models/model.rb +55 -23
- data/lib/gooddata/models/models.rb +0 -2
- data/lib/gooddata/models/module_constants.rb +0 -2
- data/lib/gooddata/models/process.rb +1 -1
- data/lib/gooddata/models/project.rb +117 -76
- data/lib/gooddata/models/project_blueprint.rb +322 -42
- data/lib/gooddata/models/project_creator.rb +5 -4
- data/lib/gooddata/models/project_role.rb +20 -55
- data/lib/gooddata/models/schema_blueprint.rb +287 -84
- data/lib/gooddata/models/schema_builder.rb +0 -4
- data/lib/gooddata/models/to_manifest.rb +160 -0
- data/lib/gooddata/models/to_wire.rb +150 -0
- data/lib/gooddata/version.rb +1 -1
- data/spec/data/blueprint_invalid.json +3 -1
- data/spec/data/gd_gse_data_blueprint.json +1370 -0
- data/spec/data/gd_gse_data_manifest.json +1424 -0
- data/spec/data/gd_gse_data_model.json +1772 -0
- data/spec/data/manifest_test_project.json +116 -0
- data/spec/data/model_view.json +1772 -0
- data/spec/data/superfluous_titles_view.json +81 -0
- data/spec/data/test_project_model_spec.json +7 -4
- data/spec/data/wire_test_project.json +143 -0
- data/spec/helpers/crypto_helper.rb +9 -0
- data/spec/helpers/project_helper.rb +2 -0
- data/spec/integration/command_projects_spec.rb +4 -2
- data/spec/integration/full_project_spec.rb +51 -18
- data/spec/integration/partial_md_export_import_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -1
- data/spec/unit/models/attribute_column_spec.rb +7 -7
- data/spec/unit/models/domain_spec.rb +2 -2
- data/spec/unit/models/from_wire_spec.rb +119 -0
- data/spec/unit/models/metadata_spec.rb +4 -2
- data/spec/unit/models/project_blueprint_spec.rb +32 -16
- data/spec/unit/models/project_role_spec.rb +6 -4
- data/spec/unit/models/project_spec.rb +26 -3
- data/spec/unit/models/schema_builder_spec.rb +5 -6
- data/spec/unit/models/to_manifest_spec.rb +24 -0
- data/spec/unit/models/to_wire_spec.rb +63 -0
- metadata +53 -29
- data/lib/gooddata/models/attributes/anchor.rb +0 -37
- data/lib/gooddata/models/attributes/attributes.rb +0 -8
- data/lib/gooddata/models/attributes/date_attribute.rb +0 -25
- data/lib/gooddata/models/attributes/time_attribute.rb +0 -24
- data/lib/gooddata/models/columns/attribute.rb +0 -71
- data/lib/gooddata/models/columns/columns.rb +0 -8
- data/lib/gooddata/models/columns/date_column.rb +0 -63
- data/lib/gooddata/models/columns/fact_model.rb +0 -54
- data/lib/gooddata/models/columns/label.rb +0 -55
- data/lib/gooddata/models/columns/reference.rb +0 -57
- data/lib/gooddata/models/facts/facts.rb +0 -8
- data/lib/gooddata/models/facts/time_fact.rb +0 -20
- data/lib/gooddata/models/folders/attribute_folder.rb +0 -20
- data/lib/gooddata/models/folders/fact_folder.rb +0 -20
- data/lib/gooddata/models/folders/folders.rb +0 -8
- data/lib/gooddata/models/metadata/column.rb +0 -61
- data/lib/gooddata/models/metadata/data_set.rb +0 -32
- data/lib/gooddata/models/metadata/date_dimension.rb +0 -26
- data/lib/gooddata/models/metadata/schema.rb +0 -227
- data/lib/gooddata/models/references/date_reference.rb +0 -44
- data/lib/gooddata/models/references/references.rb +0 -8
- data/lib/gooddata/models/references/time_reference.rb +0 -13
- data/spec/helpers/schema_helper.rb +0 -16
- data/spec/unit/models/anchor_spec.rb +0 -32
- data/spec/unit/models/tools_spec.rb +0 -95
- data/test/test_upload.rb +0 -79
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module GoodData
|
4
|
+
module Mixin
|
5
|
+
module MdObjectQuery
|
6
|
+
# Method intended to get all objects of that type in a specified project
|
7
|
+
#
|
8
|
+
# @param options [Hash] the options hash
|
9
|
+
# @option options [Boolean] :full if passed true the subclass can decide to pull in full objects. This is desirable from the usability POV but unfortunately has negative impact on performance so it is not the default
|
10
|
+
# @return [Array<GoodData::MdObject> | Array<Hash>] Return the appropriate metadata objects or their representation
|
11
|
+
def all(options = {})
|
12
|
+
fail NotImplementedError, 'Method should be implemented in subclass. Currently there is no way hoe to get all metadata objects on API.'
|
13
|
+
end
|
14
|
+
|
15
|
+
# Method intended to be called by individual classes in their all
|
16
|
+
# implementations. It abstracts the way interacting with query resources.
|
17
|
+
# It either returns the array of hashes from query. If asked it also
|
18
|
+
# goes and brings the full objects. Due to performance reasons
|
19
|
+
# :full => false is the default. This will most likely change
|
20
|
+
#
|
21
|
+
# @param query_obj_type [String] string used in URI to distinguish different query resources for different objects
|
22
|
+
# @param klass [Class] A class used for instantiating the returned data
|
23
|
+
# @param options [Hash] the options hash
|
24
|
+
# @option options [Boolean] :full if passed true the subclass can decide to pull in full objects. This is desirable from the usability POV but unfortunately has negative impact on performance so it is not the default
|
25
|
+
# @return [Array<GoodData::MdObject> | Array<Hash>] Return the appropriate metadata objects or their representation
|
26
|
+
def query(query_obj_type, klass, options = {})
|
27
|
+
fail(NoProjectError, 'Connect to a project before searching for an object') unless GoodData.project
|
28
|
+
query_result = GoodData.get(GoodData.project.md['query'] + "/#{query_obj_type}/")['query']['entries']
|
29
|
+
options[:full] ? query_result.map { |item| klass[item['link']] } : query_result
|
30
|
+
end
|
31
|
+
|
32
|
+
def dependency(uri, key = nil)
|
33
|
+
result = GoodData.get(uri)['entries']
|
34
|
+
if key.nil?
|
35
|
+
result
|
36
|
+
elsif key.respond_to?(:category)
|
37
|
+
result.select { |item| item['category'] == key.category }
|
38
|
+
else
|
39
|
+
result.select { |item| item['category'] == key }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Checks for dependency
|
44
|
+
def dependency?(type, uri, target_uri)
|
45
|
+
uri = uri.respond_to?(:uri) ? uri.uri : uri
|
46
|
+
objs = case type
|
47
|
+
when :usedby
|
48
|
+
usedby(uri)
|
49
|
+
when :using
|
50
|
+
using(uri)
|
51
|
+
end
|
52
|
+
|
53
|
+
target_uri = target_uri.respond_to?(:uri) ? target_uri.uri : target_uri
|
54
|
+
objs.any? do |obj|
|
55
|
+
obj['link'] == target_uri
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns which objects uses this MD resource
|
60
|
+
def usedby(uri, key = nil, project = GoodData.project)
|
61
|
+
dependency("#{project.md['usedby2']}/#{obj_id(uri)}", key)
|
62
|
+
end
|
63
|
+
|
64
|
+
alias_method :used_by, :usedby
|
65
|
+
|
66
|
+
# Returns which objects this MD resource uses
|
67
|
+
def using(uri, key = nil)
|
68
|
+
dependency("#{GoodData.project.md['using2']}/#{obj_id(uri)}", key)
|
69
|
+
end
|
70
|
+
|
71
|
+
def usedby?(uri, target_uri)
|
72
|
+
dependency?(:usedby, uri, target_uri)
|
73
|
+
end
|
74
|
+
|
75
|
+
alias_method :used_by?, :usedby?
|
76
|
+
|
77
|
+
# Checks if obj is using this MD resource
|
78
|
+
def using?(uri, target_uri)
|
79
|
+
dependency?(:using, uri, target_uri)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module GoodData
|
4
|
+
module Mixin
|
5
|
+
module MdRelations
|
6
|
+
def dependency(uri, key = nil)
|
7
|
+
GoodData::MdObject.dependency(uri, key)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Checks for dependency
|
11
|
+
def dependency?(type, obj)
|
12
|
+
GoodData::MdObject.dependency?(type, self, obj)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns which objects uses this MD resource
|
16
|
+
def usedby(key = nil, project = GoodData.project)
|
17
|
+
dependency("#{project.md['usedby2']}/#{obj_id}", key)
|
18
|
+
end
|
19
|
+
|
20
|
+
alias_method :used_by, :usedby
|
21
|
+
|
22
|
+
# Returns which objects this MD resource uses
|
23
|
+
def using(key = nil)
|
24
|
+
dependency("#{GoodData.project.md['using2']}/#{obj_id}", key)
|
25
|
+
end
|
26
|
+
|
27
|
+
def usedby?(obj)
|
28
|
+
GoodData::MdObject.used_by?(self, obj)
|
29
|
+
end
|
30
|
+
|
31
|
+
alias_method :used_by?, :usedby?
|
32
|
+
|
33
|
+
# Checks if obj is using this MD resource
|
34
|
+
def using?(obj)
|
35
|
+
dependency?(:using, obj)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,15 @@
|
|
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
|
+
blacklist = [
|
8
|
+
File.join(base, 'rest_getters.rb'),
|
9
|
+
File.join(base, 'rest_resource.rb')
|
10
|
+
]
|
11
|
+
|
12
|
+
require file unless blacklist.include? file
|
13
|
+
end
|
14
|
+
require_relative 'rest_getters'
|
15
|
+
require_relative 'rest_resource'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require_relative 'root_key_setter'
|
4
|
+
require_relative 'data_property_reader'
|
5
|
+
require_relative 'data_property_writer'
|
6
|
+
require_relative 'meta_property_reader'
|
7
|
+
require_relative 'meta_property_reader'
|
8
|
+
|
9
|
+
module GoodData
|
10
|
+
module Mixin
|
11
|
+
module RestResource
|
12
|
+
include GoodData::Mixin::RootKeySetter
|
13
|
+
include GoodData::Mixin::DataPropertyReader
|
14
|
+
include GoodData::Mixin::DataPropertyWriter
|
15
|
+
include GoodData::Mixin::MetaPropertyReader
|
16
|
+
include GoodData::Mixin::MetaPropertyWriter
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module GoodData
|
4
|
+
module Model
|
5
|
+
module FromWire
|
6
|
+
# Converts dataset from wire format into an internal blueprint representation
|
7
|
+
#
|
8
|
+
# @param stuff [Hash] Whatever comes from wire
|
9
|
+
# @return [Hash] Manifest for a particular reference
|
10
|
+
def self.dataset_from_wire(stuff)
|
11
|
+
Hash.new.tap do |d|
|
12
|
+
d[:type] = :dataset
|
13
|
+
d[:title] = stuff['dataset']['title'] if stuff['dataset']['title'] != stuff['dataset']['identifier'].split('.').last.titleize
|
14
|
+
d[:name] = stuff['dataset']['identifier'].split('.').last
|
15
|
+
d[:columns] = (parse_anchor(stuff) + parse_attributes(stuff) + parse_facts(stuff) + parse_references(stuff))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Entry method for converting information about project mode from wire
|
20
|
+
# format into an internal blueprint representation
|
21
|
+
#
|
22
|
+
# @param stuff [Hash] Whatever comes from wire
|
23
|
+
# @return [GoodData::Model::ProjectBlueprint] Manifest for a particular reference
|
24
|
+
def self.from_wire(stuff)
|
25
|
+
model = stuff['projectModelView']['model']['projectModel']
|
26
|
+
datasets = model['datasets'] || []
|
27
|
+
dims = model['dateDimensions'] || []
|
28
|
+
ProjectBlueprint.new(
|
29
|
+
datasets: datasets.map { |ds| dataset_from_wire(ds) },
|
30
|
+
date_dimensions: dims.map { |dd| parse_date_dimensions(dd) }
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Converts anchor from wire format into an internal blueprint representation
|
35
|
+
#
|
36
|
+
# @param stuff [Hash] Whatever comes from wire
|
37
|
+
# @return [Hash] Manifest for a particular reference
|
38
|
+
def self.parse_anchor(stuff)
|
39
|
+
attribute = stuff['dataset']['anchor']['attribute']
|
40
|
+
if !attribute.key?('labels')
|
41
|
+
[]
|
42
|
+
else
|
43
|
+
labels = attribute['labels'] || []
|
44
|
+
default_label = attribute['defaultLabel']
|
45
|
+
primary_label_name = attribute['identifier'].split('.').last
|
46
|
+
dataset_name = attribute['identifier'].split('.')[1]
|
47
|
+
primary_label_identifier = GoodData::Model.identifier_for({ name: dataset_name }, type: :primary_label, name: primary_label_name)
|
48
|
+
primary_labels, regular_labels = labels.partition { |x| x['label']['identifier'] == primary_label_identifier }
|
49
|
+
dl = primary_labels.map do |label|
|
50
|
+
parse_label(attribute, label, 'anchor', default_label)
|
51
|
+
end
|
52
|
+
rl = regular_labels.map do |label|
|
53
|
+
parse_label(attribute, label, 'label', default_label)
|
54
|
+
end
|
55
|
+
dl + rl
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Converts attrbutes from wire format into an internal blueprint representation
|
60
|
+
#
|
61
|
+
# @param stuff [Hash] Whatever comes from wire
|
62
|
+
# @return [Hash] Manifest for a particular reference
|
63
|
+
def self.parse_attributes(stuff)
|
64
|
+
dataset = stuff['dataset']
|
65
|
+
attributes = dataset['attributes'] || []
|
66
|
+
attributes.mapcat do |a|
|
67
|
+
attribute = a['attribute']
|
68
|
+
labels = attribute['labels'] || []
|
69
|
+
default_label = attribute['defaultLabel']
|
70
|
+
primary_label_name = attribute['identifier'].split('.').last
|
71
|
+
dataset_name = attribute['identifier'].split('.')[1]
|
72
|
+
primary_label_identifier = GoodData::Model.identifier_for({ name: dataset_name }, type: :primary_label, name: primary_label_name)
|
73
|
+
primary_labels, regular_labels = labels.partition { |x| x['label']['identifier'] == primary_label_identifier }
|
74
|
+
dl = primary_labels.map do |label|
|
75
|
+
parse_label(attribute, label, 'attribute', default_label)
|
76
|
+
end
|
77
|
+
rl = regular_labels.map do |label|
|
78
|
+
parse_label(attribute, label, 'label', default_label)
|
79
|
+
end
|
80
|
+
dl + rl
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Converts date dimensions from wire format into an internal blueprint representation
|
85
|
+
#
|
86
|
+
# @param stuff [Hash] Whatever comes from wire
|
87
|
+
# @return [Hash] Manifest for a particular reference
|
88
|
+
def self.parse_date_dimensions(stuff)
|
89
|
+
Hash.new.tap do |d|
|
90
|
+
d[:type] = :date_dimension
|
91
|
+
# d[:urn] = :date_dimension
|
92
|
+
d[:name] = stuff['dateDimension']['name']
|
93
|
+
d[:title] = stuff['dateDimension']['title'] if stuff['dateDimension']['title'] != stuff['dateDimension']['title'].titleize
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Converts facts from wire format into an internal blueprint representation
|
98
|
+
#
|
99
|
+
# @param stuff [Hash] Whatever comes from wire
|
100
|
+
# @return [Hash] Manifest for a particular reference
|
101
|
+
def self.parse_facts(stuff)
|
102
|
+
facts = stuff['dataset']['facts'] || []
|
103
|
+
facts.map do |fact|
|
104
|
+
Hash.new.tap do |f|
|
105
|
+
f[:type] = fact['fact']['identifier'] =~ /^dt\./ ? :date_fact : :fact
|
106
|
+
f[:name] = fact['fact']['identifier'].split('.').last
|
107
|
+
f[:title] = fact['fact']['title'] if fact['fact']['title'] != fact['fact']['identifier'].split('.').last.titleize
|
108
|
+
f[:gd_data_type] = fact['fact']['dataType'] if fact['fact'].key?('dataType')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Converts label from wire format into an internal blueprint representation
|
114
|
+
#
|
115
|
+
# @param stuff [Hash] Whatever comes from wire
|
116
|
+
# @return [Hash] Manifest for a particular reference
|
117
|
+
def self.parse_label(attribute, label, type, default_label = nil)
|
118
|
+
Hash.new.tap do |l|
|
119
|
+
l[:type] = type
|
120
|
+
l[:reference] = attribute['identifier'].split('.').last if type == 'label'
|
121
|
+
l[:name] = label['label']['identifier'].split('.').last
|
122
|
+
l[:title] = label['label']['title'] if label['label']['title'] != label['label']['identifier'].split('.').last.titleize
|
123
|
+
l[:gd_data_type] = label['label']['dataType'] if label['label'].key?('dataType')
|
124
|
+
l[:gd_type] = label['label']['type'] if label['label'].key?('type')
|
125
|
+
l[:default_label] = true if default_label == label['label']['identifier']
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Converts label from wire format into an internal blueprint representation
|
130
|
+
#
|
131
|
+
# @param stuff [Hash] Whatever comes from wire
|
132
|
+
# @return [Hash] Manifest for a particular reference
|
133
|
+
def self.parse_references(stuff)
|
134
|
+
references = stuff['dataset']['references'] || []
|
135
|
+
references.map do |ref|
|
136
|
+
if ref =~ /^dataset\./
|
137
|
+
{
|
138
|
+
:type => :reference,
|
139
|
+
:name => ref.gsub('dataset.', ''),
|
140
|
+
:dataset => ref.gsub('dataset.', '')
|
141
|
+
}
|
142
|
+
else
|
143
|
+
{
|
144
|
+
:type => :date,
|
145
|
+
:name => ref.gsub('dataset.', ''),
|
146
|
+
:dataset => ref.gsub('dataset.', '')
|
147
|
+
}
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|