gooddata 0.6.18 → 0.6.19
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.travis.yml +8 -19
- data/Guardfile +5 -0
- data/README.md +1 -3
- data/bin/gooddata +1 -1
- data/gooddata.gemspec +6 -4
- data/lib/gooddata.rb +1 -1
- data/lib/gooddata/bricks/middleware/aws_middleware.rb +24 -0
- data/lib/gooddata/cli/commands/console_cmd.rb +1 -1
- data/lib/gooddata/cli/commands/project_cmd.rb +29 -9
- data/lib/gooddata/cli/hooks.rb +9 -3
- data/lib/gooddata/commands/datawarehouse.rb +1 -7
- data/lib/gooddata/commands/project.rb +4 -3
- data/lib/gooddata/core/logging.rb +14 -2
- data/lib/gooddata/exceptions/execution_limit_exceeded.rb +9 -0
- data/lib/gooddata/exceptions/uncomputable_report.rb +8 -0
- data/lib/gooddata/exceptions/validation_error.rb +1 -1
- data/lib/gooddata/goodzilla/goodzilla.rb +5 -1
- data/lib/gooddata/helpers/data_helper.rb +40 -9
- data/lib/gooddata/mixins/md_finders.rb +35 -0
- data/lib/gooddata/models/blueprint/anchor_field.rb +46 -0
- data/lib/gooddata/models/blueprint/attribute_field.rb +25 -0
- data/lib/gooddata/models/blueprint/blueprint.rb +7 -0
- data/lib/gooddata/models/blueprint/blueprint_field.rb +66 -0
- data/lib/gooddata/models/{dashboard_builder.rb → blueprint/dashboard_builder.rb} +0 -0
- data/lib/gooddata/models/{schema_blueprint.rb → blueprint/dataset_blueprint.rb} +176 -117
- data/lib/gooddata/models/blueprint/date_dimension.rb +10 -0
- data/lib/gooddata/models/blueprint/fact_field.rb +16 -0
- data/lib/gooddata/models/blueprint/label_field.rb +39 -0
- data/lib/gooddata/models/{project_blueprint.rb → blueprint/project_blueprint.rb} +366 -168
- data/lib/gooddata/models/blueprint/project_builder.rb +79 -0
- data/lib/gooddata/models/blueprint/reference_field.rb +39 -0
- data/lib/gooddata/models/blueprint/schema_blueprint.rb +156 -0
- data/lib/gooddata/models/blueprint/schema_builder.rb +85 -0
- data/lib/gooddata/models/{to_manifest.rb → blueprint/to_manifest.rb} +25 -20
- data/lib/gooddata/models/{to_wire.rb → blueprint/to_wire.rb} +33 -52
- data/lib/gooddata/models/datawarehouse.rb +2 -2
- data/lib/gooddata/models/domain.rb +3 -2
- data/lib/gooddata/models/execution.rb +2 -2
- data/lib/gooddata/models/execution_detail.rb +7 -2
- data/lib/gooddata/models/from_wire.rb +60 -71
- data/lib/gooddata/models/from_wire_parse.rb +125 -125
- data/lib/gooddata/models/metadata.rb +14 -0
- data/lib/gooddata/models/metadata/dashboard.rb +2 -2
- data/lib/gooddata/models/metadata/label.rb +1 -1
- data/lib/gooddata/models/metadata/report.rb +6 -5
- data/lib/gooddata/models/metadata/report_definition.rb +44 -59
- data/lib/gooddata/models/model.rb +131 -43
- data/lib/gooddata/models/process.rb +13 -11
- data/lib/gooddata/models/profile.rb +12 -1
- data/lib/gooddata/models/project.rb +223 -19
- data/lib/gooddata/models/project_creator.rb +4 -15
- data/lib/gooddata/models/schedule.rb +1 -0
- data/lib/gooddata/models/user_filters/user_filter_builder.rb +2 -2
- data/lib/gooddata/rest/client.rb +18 -18
- data/lib/gooddata/rest/connection.rb +113 -94
- data/lib/gooddata/version.rb +1 -1
- data/lib/templates/project/model/model.rb.erb +15 -16
- data/spec/data/blueprints/additional_dataset_module.json +32 -0
- data/spec/data/blueprints/big_blueprint_not_pruned.json +2079 -0
- data/spec/data/blueprints/invalid_blueprint.json +103 -0
- data/spec/data/blueprints/m_n_model.json +104 -0
- data/spec/data/blueprints/model_module.json +25 -0
- data/spec/data/blueprints/test_blueprint.json +38 -0
- data/spec/data/blueprints/test_project_model_spec.json +106 -0
- data/spec/data/gd_gse_data_manifest.json +34 -34
- data/spec/data/manifests/test_blueprint.json +32 -0
- data/spec/data/{manifest_test_project.json → manifests/test_project.json} +9 -18
- data/spec/data/wire_models/test_blueprint.json +63 -0
- data/spec/data/wire_test_project.json +5 -5
- data/spec/environment/default.rb +33 -0
- data/spec/environment/develop.rb +26 -0
- data/spec/environment/environment.rb +14 -0
- data/spec/environment/hotfix.rb +17 -0
- data/spec/environment/production.rb +31 -0
- data/spec/environment/release.rb +17 -0
- data/spec/helpers/blueprint_helper.rb +10 -7
- data/spec/helpers/cli_helper.rb +24 -22
- data/spec/helpers/connection_helper.rb +27 -25
- data/spec/helpers/crypto_helper.rb +7 -5
- data/spec/helpers/csv_helper.rb +5 -3
- data/spec/helpers/process_helper.rb +15 -10
- data/spec/helpers/project_helper.rb +40 -33
- data/spec/helpers/schedule_helper.rb +15 -9
- data/spec/helpers/spec_helper.rb +11 -0
- data/spec/integration/blueprint_updates_spec.rb +93 -0
- data/spec/integration/command_datawarehouse_spec.rb +2 -1
- data/spec/integration/command_projects_spec.rb +9 -8
- data/spec/integration/create_from_template_spec.rb +1 -1
- data/spec/integration/create_project_spec.rb +1 -1
- data/spec/integration/full_process_schedule_spec.rb +1 -1
- data/spec/integration/full_project_spec.rb +91 -30
- data/spec/integration/over_to_user_filters_spec.rb +24 -28
- data/spec/integration/partial_md_export_import_spec.rb +4 -4
- data/spec/integration/project_spec.rb +1 -1
- data/spec/integration/rest_spec.rb +1 -1
- data/spec/integration/user_filters_spec.rb +19 -24
- data/spec/integration/variables_spec.rb +7 -9
- data/spec/logging_in_logging_out_spec.rb +1 -1
- data/spec/spec_helper.rb +10 -1
- data/spec/unit/bricks/middleware/aws_middelware_spec.rb +47 -0
- data/spec/unit/core/connection_spec.rb +2 -2
- data/spec/unit/core/logging_spec.rb +12 -4
- data/spec/unit/helpers/data_helper_spec.rb +60 -0
- data/spec/unit/models/blueprint/attributes_spec.rb +24 -0
- data/spec/unit/models/blueprint/dataset_spec.rb +116 -0
- data/spec/unit/models/blueprint/labels_spec.rb +39 -0
- data/spec/unit/models/blueprint/project_blueprint_spec.rb +643 -0
- data/spec/unit/models/blueprint/reference_spec.rb +24 -0
- data/spec/unit/models/{schema_builder_spec.rb → blueprint/schema_builder_spec.rb} +12 -4
- data/spec/unit/models/blueprint/to_wire_spec.rb +169 -0
- data/spec/unit/models/domain_spec.rb +13 -2
- data/spec/unit/models/from_wire_spec.rb +277 -98
- data/spec/unit/models/metadata_spec.rb +22 -4
- data/spec/unit/models/model_spec.rb +49 -39
- data/spec/unit/models/profile_spec.rb +1 -0
- data/spec/unit/models/project_spec.rb +7 -7
- data/spec/unit/models/schedule_spec.rb +20 -0
- data/spec/unit/models/to_manifest_spec.rb +31 -11
- data/spec/unit/rest/polling_spec.rb +86 -0
- metadata +102 -30
- data/lib/gooddata/models/project_builder.rb +0 -136
- data/lib/gooddata/models/schema_builder.rb +0 -77
- data/out.txt +0 -0
- data/spec/data/additional_dataset_module.json +0 -18
- data/spec/data/blueprint_invalid.json +0 -38
- data/spec/data/m_n_model/blueprint.json +0 -76
- data/spec/data/model_module.json +0 -18
- data/spec/data/test_project_model_spec.json +0 -76
- data/spec/unit/models/attribute_column_spec.rb +0 -7
- data/spec/unit/models/project_blueprint_spec.rb +0 -239
- data/spec/unit/models/to_wire_spec.rb +0 -71
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require_relative 'blueprint_field'
|
|
4
|
+
|
|
5
|
+
module GoodData
|
|
6
|
+
module Model
|
|
7
|
+
class FactBlueprintField < BlueprintField
|
|
8
|
+
# Returns gd_data_type
|
|
9
|
+
#
|
|
10
|
+
# @return [String] returns gd_data_type of the fact
|
|
11
|
+
def gd_data_type
|
|
12
|
+
data[:gd_data_type] || Model::DEFAULT_FACT_DATATYPE
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require_relative 'blueprint_field'
|
|
4
|
+
|
|
5
|
+
module GoodData
|
|
6
|
+
module Model
|
|
7
|
+
class LabelBlueprintField < BlueprintField
|
|
8
|
+
# Returns the attribute this label is referencing to
|
|
9
|
+
#
|
|
10
|
+
# @return [AttributeBlueprintField] the object representing attribute in the blueprint
|
|
11
|
+
def attribute
|
|
12
|
+
dataset_blueprint.attribute_for_label(self)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Returns gd_data_type
|
|
16
|
+
#
|
|
17
|
+
# @return [String] returns gd_data_type of the label
|
|
18
|
+
def gd_data_type
|
|
19
|
+
data[:gd_data_type] || Model::DEFAULT_ATTRIBUTE_DATATYPE
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns gd_data_type
|
|
23
|
+
#
|
|
24
|
+
# @return [String] returns gd_type of the label
|
|
25
|
+
def gd_type
|
|
26
|
+
data[:gd_type] || Model::DEFAULT_TYPE
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Validates the fields in the label
|
|
30
|
+
#
|
|
31
|
+
# @return [Array] returns list of the errors represented by hash structures
|
|
32
|
+
def validate
|
|
33
|
+
validate_presence_of(:id, :reference).map do |e|
|
|
34
|
+
{ type: :error, message: "Field \"#{e}\" is not defined or empty for label \"#{id}\"" }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -29,14 +29,27 @@ module GoodData
|
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
# Removes column from from the blueprint
|
|
33
|
+
#
|
|
34
|
+
# @param project [Hash | GoodData::Model::ProjectBlueprint] Project blueprint
|
|
35
|
+
# @param dataset [Hash | GoodData::Model::DatasetBlueprint] Dataset blueprint
|
|
36
|
+
# @param column_id [String] Column id
|
|
37
|
+
# @return [Hash | GoodData::Model::ProjectBlueprint] Returns changed blueprint
|
|
38
|
+
def self.remove_column!(project, dataset, column_id)
|
|
39
|
+
dataset = find_dataset(project, dataset)
|
|
40
|
+
col = dataset[:columns].find { |c| c[:id] == column_id }
|
|
41
|
+
dataset[:columns].delete(col)
|
|
42
|
+
project
|
|
43
|
+
end
|
|
44
|
+
|
|
32
45
|
# Removes dataset from blueprint. Dataset can be given as either a name
|
|
33
46
|
# or a DatasetBlueprint or a Hash representation.
|
|
34
47
|
#
|
|
35
|
-
# @param project [Hash] Project blueprint
|
|
48
|
+
# @param project [Hash | GoodData::Model::ProjectBlueprint] Project blueprint
|
|
36
49
|
# @param dataset_name [GoodData::Model::DatasetBlueprint | String | Hash] Dataset to be removed
|
|
37
|
-
# @return [Hash] project with removed dataset
|
|
38
|
-
def self.remove_dataset(project,
|
|
39
|
-
dataset =
|
|
50
|
+
# @return [Hash] new project with removed dataset
|
|
51
|
+
def self.remove_dataset(project, dataset_id)
|
|
52
|
+
dataset = dataset_id.is_a?(String) ? find_dataset(project, dataset_id) : dataset_name
|
|
40
53
|
index = project[:datasets].index(dataset)
|
|
41
54
|
dupped_project = project.deep_dup
|
|
42
55
|
dupped_project[:datasets].delete_at(index)
|
|
@@ -47,11 +60,12 @@ module GoodData
|
|
|
47
60
|
# or a DatasetBlueprint or a Hash representation. This version mutates
|
|
48
61
|
# the dataset in place
|
|
49
62
|
#
|
|
50
|
-
# @param project [Hash] Project blueprint
|
|
63
|
+
# @param project [Hash | GoodData::Model::ProjectBlueprint] Project blueprint
|
|
51
64
|
# @param dataset_name [GoodData::Model::DatasetBlueprint | String | Hash] Dataset to be removed
|
|
52
65
|
# @return [Hash] project with removed dataset
|
|
53
|
-
def self.remove_dataset!(project,
|
|
54
|
-
|
|
66
|
+
def self.remove_dataset!(project, dataset_id)
|
|
67
|
+
project = project.to_hash
|
|
68
|
+
dataset = dataset_id.is_a?(String) ? find_dataset(project, dataset_id) : dataset_id
|
|
55
69
|
index = project[:datasets].index(dataset)
|
|
56
70
|
project[:datasets].delete_at(index)
|
|
57
71
|
project
|
|
@@ -63,11 +77,12 @@ module GoodData
|
|
|
63
77
|
# @param project [GoodData::Model::ProjectBlueprint | Hash] Project blueprint
|
|
64
78
|
# @param options [Hash] options
|
|
65
79
|
# @return [Array<Hash>]
|
|
66
|
-
def self.datasets(
|
|
80
|
+
def self.datasets(project_blueprint, options = {})
|
|
81
|
+
project_blueprint = project_blueprint.to_hash
|
|
67
82
|
include_date_dimensions = options[:include_date_dimensions] || options[:dd]
|
|
68
|
-
ds = (
|
|
83
|
+
ds = (project_blueprint.to_hash[:datasets] || [])
|
|
69
84
|
if include_date_dimensions
|
|
70
|
-
ds + date_dimensions(
|
|
85
|
+
ds + date_dimensions(project_blueprint)
|
|
71
86
|
else
|
|
72
87
|
ds
|
|
73
88
|
end
|
|
@@ -78,8 +93,8 @@ module GoodData
|
|
|
78
93
|
# @param project [GoodData::Model::ProjectBlueprint | Hash] Project blueprint
|
|
79
94
|
# @param name [GoodData::Model::DatasetBlueprint | String | Hash] Dataset
|
|
80
95
|
# @return [Boolean]
|
|
81
|
-
def self.dataset?(project, name)
|
|
82
|
-
find_dataset(project, name)
|
|
96
|
+
def self.dataset?(project, name, options = {})
|
|
97
|
+
find_dataset(project, name, options)
|
|
83
98
|
true
|
|
84
99
|
rescue
|
|
85
100
|
false
|
|
@@ -91,16 +106,11 @@ module GoodData
|
|
|
91
106
|
# @param obj [GoodData::Model::DatasetBlueprint | String | Hash] Dataset
|
|
92
107
|
# @param options [Hash] options
|
|
93
108
|
# @return [GoodData::Model::DatasetBlueprint]
|
|
94
|
-
def self.find_dataset(
|
|
95
|
-
include_date_dimensions = options[:include_date_dimensions] || options[:dd]
|
|
109
|
+
def self.find_dataset(project_blueprint, obj, options = {})
|
|
96
110
|
return obj.to_hash if DatasetBlueprint.dataset_blueprint?(obj)
|
|
97
|
-
all_datasets =
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
datasets(project)
|
|
101
|
-
end
|
|
102
|
-
name = obj.respond_to?(:key?) ? obj[:name] : obj
|
|
103
|
-
ds = all_datasets.find { |d| d[:name] == name }
|
|
111
|
+
all_datasets = datasets(project_blueprint, options)
|
|
112
|
+
name = obj.respond_to?(:to_hash) ? obj.to_hash[:id] : obj
|
|
113
|
+
ds = all_datasets.find { |d| d[:id] == name }
|
|
104
114
|
fail "Dataset #{name} could not be found" if ds.nil?
|
|
105
115
|
ds
|
|
106
116
|
end
|
|
@@ -109,8 +119,9 @@ module GoodData
|
|
|
109
119
|
#
|
|
110
120
|
# @param project [GoodData::Model::ProjectBlueprint | Hash] Project blueprint
|
|
111
121
|
# @return [Array<Hash>]
|
|
112
|
-
def self.date_dimensions(
|
|
113
|
-
|
|
122
|
+
def self.date_dimensions(project_blueprint)
|
|
123
|
+
project_blueprint.to_hash[:date_dimensions] || []
|
|
124
|
+
# dims.map {|dim| DateDimension.new(dim, project_blueprint)}
|
|
114
125
|
end
|
|
115
126
|
|
|
116
127
|
# Returns true if a date dimension of a given name exists in a bleuprint
|
|
@@ -132,8 +143,8 @@ module GoodData
|
|
|
132
143
|
# @param name [string] Date dimension
|
|
133
144
|
# @return [Hash]
|
|
134
145
|
def self.find_date_dimension(project, name)
|
|
135
|
-
ds = date_dimensions(project).find { |d| d[:
|
|
136
|
-
fail "Date dimension #{name} could not be found"
|
|
146
|
+
ds = date_dimensions(project).find { |d| d[:id] == name }
|
|
147
|
+
fail "Date dimension #{name} could not be found" unless ds
|
|
137
148
|
ds
|
|
138
149
|
end
|
|
139
150
|
|
|
@@ -145,6 +156,10 @@ module GoodData
|
|
|
145
156
|
datasets(project).mapcat { |d| DatasetBlueprint.fields(d) }
|
|
146
157
|
end
|
|
147
158
|
|
|
159
|
+
# Changes the dataset through a builder. You provide a block and an istance of
|
|
160
|
+
# GoodData::Model::ProjectBuilder is passed in as the only parameter
|
|
161
|
+
#
|
|
162
|
+
# @return [GoodData::Model::ProjectBlueprint] returns changed project blueprint
|
|
148
163
|
def change(&block)
|
|
149
164
|
builder = ProjectBuilder.create_from_data(self)
|
|
150
165
|
block.call(builder)
|
|
@@ -157,34 +172,132 @@ module GoodData
|
|
|
157
172
|
#
|
|
158
173
|
# @param options [Hash] options
|
|
159
174
|
# @return [Array<GoodData::Model::DatasetBlueprint>]
|
|
160
|
-
def datasets(options = {})
|
|
161
|
-
|
|
175
|
+
def datasets(id = :all, options = {})
|
|
176
|
+
id = id.respond_to?(:id) ? id.id : id
|
|
177
|
+
dss = ProjectBlueprint.datasets(self, options).map do |d|
|
|
178
|
+
case d[:type]
|
|
179
|
+
when :date_dimension
|
|
180
|
+
DateDimension.new(d, self)
|
|
181
|
+
when :dataset
|
|
182
|
+
DatasetBlueprint.new(d, self)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
id == :all ? dss : dss.find { |d| d.id == id }
|
|
162
186
|
end
|
|
163
187
|
|
|
188
|
+
# Adds dataset to the blueprint
|
|
189
|
+
#
|
|
190
|
+
# @param a_dataset [Hash | GoodData::Model::SchemaBlueprint] dataset to be added
|
|
191
|
+
# @param index [Integer] number specifying at which position the new dataset should be added. If not specified it is added at the end
|
|
192
|
+
# @return [GoodData::Model::ProjectBlueprint] returns project blueprint
|
|
164
193
|
def add_dataset!(a_dataset, index = nil)
|
|
165
194
|
if index.nil? || index > datasets.length
|
|
166
195
|
data[:datasets] << a_dataset.to_hash
|
|
167
196
|
else
|
|
168
197
|
data[:datasets].insert(index, a_dataset.to_hash)
|
|
169
198
|
end
|
|
199
|
+
self
|
|
170
200
|
end
|
|
171
201
|
|
|
172
|
-
|
|
173
|
-
|
|
202
|
+
def add_date_dimension!(a_dimension, index = nil)
|
|
203
|
+
dim = a_dimension.to_hash
|
|
204
|
+
if index.nil? || index > date_dimensions.length
|
|
205
|
+
data[:date_dimensions] << dim
|
|
206
|
+
else
|
|
207
|
+
data[:date_dimensions].insert(index, dim)
|
|
208
|
+
end
|
|
209
|
+
self
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Adds column to particular dataset in the blueprint
|
|
174
213
|
#
|
|
175
|
-
# @param
|
|
176
|
-
# @
|
|
177
|
-
|
|
178
|
-
|
|
214
|
+
# @param dataset [Hash | GoodData::Model::SchemaBlueprint] dataset to be added
|
|
215
|
+
# @param column_definition [Hash] Column definition to be added
|
|
216
|
+
# @return [GoodData::Model::ProjectBlueprint] returns project blueprint
|
|
217
|
+
def add_column!(dataset, column_definition)
|
|
218
|
+
ds = ProjectBlueprint.find_dataset(to_hash, dataset)
|
|
219
|
+
ds[:columns] << column_definition
|
|
220
|
+
self
|
|
179
221
|
end
|
|
180
222
|
|
|
181
|
-
# Removes
|
|
182
|
-
# or a DatasetBlueprint or a Hash representation.
|
|
223
|
+
# Removes column to particular dataset in the blueprint
|
|
183
224
|
#
|
|
184
|
-
# @param
|
|
185
|
-
# @
|
|
186
|
-
|
|
187
|
-
|
|
225
|
+
# @param dataset [Hash | GoodData::Model::SchemaBlueprint] dataset to be added
|
|
226
|
+
# @param id [String] id of the column to be removed
|
|
227
|
+
# @return [GoodData::Model::ProjectBlueprint] returns project blueprint
|
|
228
|
+
def remove_column!(dataset, id)
|
|
229
|
+
ProjectBlueprint.remove_column!(to_hash, dataset, id)
|
|
230
|
+
self
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Moves column to particular dataset in the blueprint. It currently supports moving
|
|
234
|
+
# of attributes and facts only. The rest of the fields probably does not make sense
|
|
235
|
+
# In case of attribute it moves its labels as well.
|
|
236
|
+
#
|
|
237
|
+
# @param id [GoodData::Model::BlueprintField] column to be moved
|
|
238
|
+
# @param from_dataset [Hash | GoodData::Model::SchemaBlueprint] dataset from which the field should be moved
|
|
239
|
+
# @param to_dataset [Hash | GoodData::Model::SchemaBlueprint] dataset to which the field should be moved
|
|
240
|
+
# @return [GoodData::Model::ProjectBlueprint] returns project blueprint
|
|
241
|
+
def move!(col, from_dataset, to_dataset)
|
|
242
|
+
from_dataset = find_dataset(from_dataset)
|
|
243
|
+
to_dataset = find_dataset(to_dataset)
|
|
244
|
+
column = if col.is_a?(String)
|
|
245
|
+
from_dataset.find_column_by_id(col)
|
|
246
|
+
else
|
|
247
|
+
from_dataset.find_column(col)
|
|
248
|
+
end
|
|
249
|
+
fail "Column #{col} cannot be found in dataset #{from_dataset.id}" unless column
|
|
250
|
+
stuff = case column.type
|
|
251
|
+
when :attribute
|
|
252
|
+
[column] + column.labels
|
|
253
|
+
when :fact
|
|
254
|
+
[column]
|
|
255
|
+
when :reference
|
|
256
|
+
[column]
|
|
257
|
+
else
|
|
258
|
+
fail 'Duplicate does not support moving #{col.type} type of field'
|
|
259
|
+
end
|
|
260
|
+
stuff = stuff.map(&:data)
|
|
261
|
+
stuff.each { |c| remove_column!(from_dataset, c[:id]) }
|
|
262
|
+
stuff.each { |c| add_column!(to_dataset, c) }
|
|
263
|
+
self
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def duplicate!(col, from_dataset, to_dataset)
|
|
267
|
+
from_dataset = find_dataset(from_dataset)
|
|
268
|
+
to_dataset = find_dataset(to_dataset)
|
|
269
|
+
column = if col.is_a?(String)
|
|
270
|
+
from_dataset.find_column_by_id(col)
|
|
271
|
+
else
|
|
272
|
+
from_dataset.find_column(col)
|
|
273
|
+
end
|
|
274
|
+
fail "Column #{col} cannot be found in dataset #{from_dataset.id}" unless column
|
|
275
|
+
stuff = case column.type
|
|
276
|
+
when :attribute
|
|
277
|
+
[column] + column.labels
|
|
278
|
+
when :fact
|
|
279
|
+
[column]
|
|
280
|
+
when :reference
|
|
281
|
+
[column]
|
|
282
|
+
else
|
|
283
|
+
fail 'Duplicate does not support moving #{col.type} type of field'
|
|
284
|
+
end
|
|
285
|
+
stuff.map(&:data).each { |c| add_column!(to_dataset, c) }
|
|
286
|
+
self
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# Returns list of attributes from all the datasets in a blueprint
|
|
290
|
+
#
|
|
291
|
+
# @return [Array<Hash>]
|
|
292
|
+
def attributes
|
|
293
|
+
datasets.reduce([]) { |a, e| a.concat(e.attributes) }
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# Returns list of attributes and anchors from all the datasets in a blueprint
|
|
297
|
+
#
|
|
298
|
+
# @return [Array<Hash>]
|
|
299
|
+
def attributes_and_anchors
|
|
300
|
+
datasets.mapcat(&:attributes_and_anchors)
|
|
188
301
|
end
|
|
189
302
|
|
|
190
303
|
# Is this a project blueprint?
|
|
@@ -198,15 +311,48 @@ module GoodData
|
|
|
198
311
|
#
|
|
199
312
|
# @return [Array<Hash>]
|
|
200
313
|
def date_dimensions
|
|
201
|
-
ProjectBlueprint.date_dimensions(
|
|
314
|
+
ProjectBlueprint.date_dimensions(self).map { |dd| GoodData::Model::DateDimension.new(dd, self) }
|
|
202
315
|
end
|
|
203
316
|
|
|
204
317
|
# Returns true if a dataset contains a particular dataset false otherwise
|
|
205
318
|
#
|
|
206
319
|
# @param name [GoodData::Model::DatasetBlueprint | String | Hash] Dataset
|
|
207
320
|
# @return [Boolean]
|
|
208
|
-
def dataset?(name)
|
|
209
|
-
ProjectBlueprint.dataset?(to_hash, name)
|
|
321
|
+
def dataset?(name, options = {})
|
|
322
|
+
ProjectBlueprint.dataset?(to_hash, name, options)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# Returns SLI manifest for one dataset. This is used by our API to allow
|
|
326
|
+
# loading data. The method is on project blueprint because you need
|
|
327
|
+
# acces to whole project to be able to generate references
|
|
328
|
+
#
|
|
329
|
+
# @param dataset [GoodData::Model::DatasetBlueprint | Hash | String] Dataset
|
|
330
|
+
# @param mode [String] Method of loading. FULL or INCREMENTAL
|
|
331
|
+
# @return [Array<Hash>] a title
|
|
332
|
+
def dataset_to_manifest(dataset, mode = 'FULL')
|
|
333
|
+
ToManifest.dataset_to_manifest(self, dataset, mode)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# Duplicated blueprint
|
|
337
|
+
#
|
|
338
|
+
# @param a_blueprint [GoodData::Model::DatasetBlueprint] Dataset blueprint to be merged
|
|
339
|
+
# @return [GoodData::Model::DatasetBlueprint]
|
|
340
|
+
def dup
|
|
341
|
+
ProjectBlueprint.new(data.deep_dup)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Returns list of facts from all the datasets in a blueprint
|
|
345
|
+
#
|
|
346
|
+
# @return [Array<Hash>]
|
|
347
|
+
def facts
|
|
348
|
+
datasets.mapcat(&:facts)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
# Returns list of fields from all the datasets in a blueprint
|
|
352
|
+
#
|
|
353
|
+
# @return [Array<Hash>]
|
|
354
|
+
def fields
|
|
355
|
+
datasets.flat_map(&:fields)
|
|
210
356
|
end
|
|
211
357
|
|
|
212
358
|
# Returns dataset specified. It can check even for a date dimension
|
|
@@ -215,7 +361,9 @@ module GoodData
|
|
|
215
361
|
# @param options [Hash] options
|
|
216
362
|
# @return [GoodData::Model::DatasetBlueprint]
|
|
217
363
|
def find_dataset(name, options = {})
|
|
218
|
-
|
|
364
|
+
ds = datasets(name, options)
|
|
365
|
+
fail "Dataset \"#{name}\" could not be found" unless ds
|
|
366
|
+
ds
|
|
219
367
|
end
|
|
220
368
|
|
|
221
369
|
# Returns a dataset of a given name. If a dataset is not found it throws an exeception
|
|
@@ -227,6 +375,15 @@ module GoodData
|
|
|
227
375
|
DatasetBlueprint.new(ds)
|
|
228
376
|
end
|
|
229
377
|
|
|
378
|
+
# Return list of datasets that are centers of the stars in datamart.
|
|
379
|
+
# This means these datasets are not referenced by anybody else
|
|
380
|
+
# In a good blueprint design these should be fact tables
|
|
381
|
+
#
|
|
382
|
+
# @return [Array<Hash>]
|
|
383
|
+
def find_star_centers
|
|
384
|
+
datasets.select { |d| d.referenced_by.empty? }
|
|
385
|
+
end
|
|
386
|
+
|
|
230
387
|
# Constructor
|
|
231
388
|
#
|
|
232
389
|
# @param init_data [ProjectBlueprint | Hash] Blueprint or a blueprint definition. If passed a hash it is used as data for new instance. If there is a ProjectBlueprint passed it is duplicated and a new instance is created.
|
|
@@ -239,65 +396,20 @@ module GoodData
|
|
|
239
396
|
else
|
|
240
397
|
init_data
|
|
241
398
|
end
|
|
242
|
-
@data = some_data.deep_dup
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
# @return [Array] array of errors
|
|
248
|
-
def validate_references
|
|
249
|
-
if datasets.count == 1
|
|
250
|
-
[]
|
|
251
|
-
else
|
|
252
|
-
x = datasets.reduce([]) { |a, e| e.anchor? ? a << [e.name] : a } + date_dimensions.map { |y| [y[:name]] }
|
|
253
|
-
refs = datasets.reduce([]) do |a, e|
|
|
254
|
-
a.concat(e.references)
|
|
255
|
-
end
|
|
256
|
-
refs.reduce([]) do |a, e|
|
|
257
|
-
x.include?([e[:dataset]]) ? a : a.concat([e])
|
|
399
|
+
@data = some_data.deep_dup.symbolize_keys
|
|
400
|
+
(@data[:datasets] || []).each do |d|
|
|
401
|
+
d[:type] = d[:type].to_sym
|
|
402
|
+
d[:columns].each do |c|
|
|
403
|
+
c[:type] = c[:type].to_sym
|
|
258
404
|
end
|
|
259
405
|
end
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
# Validate the blueprint and all its datasets return array of errors that are found.
|
|
263
|
-
#
|
|
264
|
-
# @return [Array] array of errors
|
|
265
|
-
def validate
|
|
266
|
-
refs_errors = validate_references
|
|
267
|
-
labels_errors = datasets.reduce([]) { |a, e| a.concat(e.validate) }
|
|
268
|
-
refs_errors.concat(labels_errors)
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
# Validate the blueprint and all its datasets and return true if model is valid. False otherwise.
|
|
272
|
-
#
|
|
273
|
-
# @return [Boolean] is model valid?
|
|
274
|
-
def valid?
|
|
275
|
-
validate.empty?
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
# Returns list of datasets which are referenced by given dataset. This can be
|
|
279
|
-
# optionally switched to return even date dimensions
|
|
280
|
-
#
|
|
281
|
-
# @param project [GoodData::Model::DatasetBlueprint | Hash | String] Dataset blueprint
|
|
282
|
-
# @return [Array<Hash>]
|
|
283
|
-
def referenced_by(dataset)
|
|
284
|
-
find_dataset(dataset, include_date_dimensions: true).references.map do |ref|
|
|
285
|
-
find_dataset(ref[:dataset], include_date_dimensions: true)
|
|
406
|
+
(@data[:date_dimensions] || []).each do |d|
|
|
407
|
+
d[:type] = d[:type].to_sym
|
|
286
408
|
end
|
|
287
409
|
end
|
|
288
410
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
# @return [Array<Hash>]
|
|
292
|
-
def attributes
|
|
293
|
-
datasets.reduce([]) { |a, e| a.concat(e.attributes) }
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
# Returns list of attributes and anchors from all the datasets in a blueprint
|
|
297
|
-
#
|
|
298
|
-
# @return [Array<Hash>]
|
|
299
|
-
def attributes_and_anchors
|
|
300
|
-
datasets.mapcat(&:attributes_and_anchors)
|
|
411
|
+
def id
|
|
412
|
+
data[:id]
|
|
301
413
|
end
|
|
302
414
|
|
|
303
415
|
# Returns list of labels from all the datasets in a blueprint
|
|
@@ -307,36 +419,6 @@ module GoodData
|
|
|
307
419
|
datasets.mapcat(&:labels)
|
|
308
420
|
end
|
|
309
421
|
|
|
310
|
-
# Returns list of facts from all the datasets in a blueprint
|
|
311
|
-
#
|
|
312
|
-
# @return [Array<Hash>]
|
|
313
|
-
def facts
|
|
314
|
-
datasets.mapcat(&:facts)
|
|
315
|
-
end
|
|
316
|
-
|
|
317
|
-
# Returns list of fields from all the datasets in a blueprint
|
|
318
|
-
#
|
|
319
|
-
# @return [Array<Hash>]
|
|
320
|
-
def fields
|
|
321
|
-
ProjectBlueprint.fields(to_hash)
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
# Returns list of attributes that can break facts in a given dataset.
|
|
325
|
-
# This basically means that it is giving you all attributes from the
|
|
326
|
-
# datasets that are references by given dataset. Currently does not
|
|
327
|
-
# work transitively
|
|
328
|
-
#
|
|
329
|
-
# @param project [GoodData::Model::DatasetBlueprint | Hash | String] Dataset blueprint
|
|
330
|
-
# @return [Array<Hash>]
|
|
331
|
-
def can_break(dataset)
|
|
332
|
-
dataset = find_dataset(dataset) if dataset.is_a?(String)
|
|
333
|
-
(referenced_by(dataset) + [dataset]).mapcat do |ds|
|
|
334
|
-
ds.attributes_and_anchors.map do |attr|
|
|
335
|
-
[ds, attr]
|
|
336
|
-
end
|
|
337
|
-
end
|
|
338
|
-
end
|
|
339
|
-
|
|
340
422
|
# Experimental but a basis for automatic check of health of a project
|
|
341
423
|
#
|
|
342
424
|
# @param project [GoodData::Model::DatasetBlueprint | Hash | String] Dataset blueprint
|
|
@@ -380,16 +462,61 @@ module GoodData
|
|
|
380
462
|
errors
|
|
381
463
|
end
|
|
382
464
|
|
|
383
|
-
#
|
|
384
|
-
# This means these datasets are not referenced by anybody else
|
|
385
|
-
# In a good blueprint design these should be fact tables
|
|
465
|
+
# Merging two blueprints. The self blueprint is changed in place
|
|
386
466
|
#
|
|
467
|
+
# @param a_blueprint [GoodData::Model::DatasetBlueprint] Dataset blueprint to be merged
|
|
468
|
+
# @return [GoodData::Model::ProjectBlueprint]
|
|
469
|
+
def merge!(a_blueprint)
|
|
470
|
+
temp_blueprint = merge(a_blueprint)
|
|
471
|
+
@data = temp_blueprint.data
|
|
472
|
+
self
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
# Returns list of datasets which are referenced by given dataset. This can be
|
|
476
|
+
# optionally switched to return even date dimensions
|
|
477
|
+
#
|
|
478
|
+
# @param project [GoodData::Model::DatasetBlueprint | Hash | String] Dataset blueprint
|
|
387
479
|
# @return [Array<Hash>]
|
|
388
|
-
def
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
480
|
+
def referenced_by(dataset)
|
|
481
|
+
find_dataset(dataset, include_date_dimensions: true).referencing
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
def referencing(dataset)
|
|
485
|
+
datasets(:all, include_date_dimensions: true)
|
|
486
|
+
.flat_map(&:references)
|
|
487
|
+
.select { |r| r.dataset == dataset }
|
|
488
|
+
.map(&:dataset_blueprint)
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
# Removes dataset from blueprint. Dataset can be given as either a name
|
|
492
|
+
# or a DatasetBlueprint or a Hash representation.
|
|
493
|
+
#
|
|
494
|
+
# @param dataset_name [GoodData::Model::DatasetBlueprint | String | Hash] Dataset to be removed
|
|
495
|
+
# @return [Hash] project with removed dataset
|
|
496
|
+
def remove_dataset(dataset_name)
|
|
497
|
+
ProjectBlueprint.remove_dataset(to_hash, dataset_name)
|
|
498
|
+
self
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
# Removes dataset from blueprint. Dataset can be given as either a name
|
|
502
|
+
# or a DatasetBlueprint or a Hash representation.
|
|
503
|
+
#
|
|
504
|
+
# @param dataset_name [GoodData::Model::DatasetBlueprint | String | Hash] Dataset to be removed
|
|
505
|
+
# @return [Hash] project with removed dataset
|
|
506
|
+
def remove_dataset!(dataset_id)
|
|
507
|
+
ProjectBlueprint.remove_dataset!(to_hash, dataset_id)
|
|
508
|
+
self
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
# Removes all the labels from the anchor. This is a typical operation that people want to
|
|
512
|
+
# perform on fact tables
|
|
513
|
+
#
|
|
514
|
+
# @return [GoodData::Model::ProjectBlueprint] Returns changed blueprint
|
|
515
|
+
def strip_anchor!(dataset)
|
|
516
|
+
from_dataset = find_dataset(dataset)
|
|
517
|
+
stuff = dataset.anchor.labels.map(&:data)
|
|
518
|
+
stuff.each { |column| remove_column!(from_dataset, column[:id]) }
|
|
519
|
+
self
|
|
393
520
|
end
|
|
394
521
|
|
|
395
522
|
# Returns some reports that might get you started. They are just simple
|
|
@@ -405,8 +532,7 @@ module GoodData
|
|
|
405
532
|
star, metrics = e
|
|
406
533
|
metrics.each(&:save)
|
|
407
534
|
reports_stubs = metrics.map do |m|
|
|
408
|
-
breaks =
|
|
409
|
-
# [breaks.sample((breaks.length/10.0).ceil), m]
|
|
535
|
+
breaks = broken_by(star).map { |ds, aM| ds.identifier_for(aM) }
|
|
410
536
|
[breaks, m]
|
|
411
537
|
end
|
|
412
538
|
a.concat(reports_stubs)
|
|
@@ -435,13 +561,41 @@ module GoodData
|
|
|
435
561
|
stars.zip(metrics)
|
|
436
562
|
end
|
|
437
563
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
def
|
|
443
|
-
|
|
444
|
-
|
|
564
|
+
def to_blueprint
|
|
565
|
+
self
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
def refactor_split_df(dataset)
|
|
569
|
+
fail ValidationError unless valid?
|
|
570
|
+
o = find_dataset(dataset)
|
|
571
|
+
new_dataset = GoodData::Model::DatasetBlueprint.new({ type: :dataset, id: "#{o.id}_dim", columns: [] }, self)
|
|
572
|
+
new_dataset.change do |d|
|
|
573
|
+
d.add_anchor('vymysli_id')
|
|
574
|
+
d.add_label('label.vymysli_id', reference: 'vymysli_id')
|
|
575
|
+
end
|
|
576
|
+
nb = merge(new_dataset.to_blueprint)
|
|
577
|
+
o.attributes.each { |a| nb.move!(a, o, new_dataset.id) }
|
|
578
|
+
old = nb.find_dataset(dataset)
|
|
579
|
+
old.attributes.each do |a|
|
|
580
|
+
remove_column!(old, a)
|
|
581
|
+
end
|
|
582
|
+
old.change do |d|
|
|
583
|
+
d.add_reference(new_dataset.id)
|
|
584
|
+
end
|
|
585
|
+
nb
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
def refactor_split_facts(dataset, column_names, new_dataset_title)
|
|
589
|
+
fail ValidationError unless valid?
|
|
590
|
+
change do |p|
|
|
591
|
+
p.add_dataset(new_dataset_title) do |d|
|
|
592
|
+
d.add_anchor("#{new_dataset_title}.id")
|
|
593
|
+
end
|
|
594
|
+
end
|
|
595
|
+
dataset_to_refactor = find_dataset(dataset)
|
|
596
|
+
new_dataset = find_dataset(new_dataset_title)
|
|
597
|
+
column_names.each { |c| move!(c, dataset_to_refactor, new_dataset) }
|
|
598
|
+
dataset_to_refactor.references.each { |ref| duplicate!(ref, dataset_to_refactor, new_dataset) }
|
|
445
599
|
self
|
|
446
600
|
end
|
|
447
601
|
|
|
@@ -454,32 +608,48 @@ module GoodData
|
|
|
454
608
|
temp_blueprint = dup
|
|
455
609
|
return temp_blueprint unless a_blueprint
|
|
456
610
|
a_blueprint.datasets.each do |dataset|
|
|
457
|
-
if temp_blueprint.dataset?(dataset.
|
|
458
|
-
local_dataset = temp_blueprint.find_dataset(dataset.
|
|
611
|
+
if temp_blueprint.dataset?(dataset.id)
|
|
612
|
+
local_dataset = temp_blueprint.find_dataset(dataset.id)
|
|
459
613
|
index = temp_blueprint.datasets.index(local_dataset)
|
|
460
614
|
local_dataset.merge!(dataset)
|
|
461
|
-
temp_blueprint.remove_dataset!(local_dataset.
|
|
615
|
+
temp_blueprint.remove_dataset!(local_dataset.id)
|
|
462
616
|
temp_blueprint.add_dataset!(local_dataset, index)
|
|
463
617
|
else
|
|
464
618
|
temp_blueprint.add_dataset!(dataset.dup)
|
|
465
619
|
end
|
|
466
620
|
end
|
|
621
|
+
a_blueprint.date_dimensions.each do |dd|
|
|
622
|
+
if temp_blueprint.dataset?(dd.id, dd: true)
|
|
623
|
+
local_dim = temp_blueprint.find_dataset(dd.id, dd: true)
|
|
624
|
+
fail "Unable to merge date dimensions #{dd.id} with defintion #{dd.data} with #{local_dim.data}" unless local_dim.data == dd.data
|
|
625
|
+
else
|
|
626
|
+
temp_blueprint.add_date_dimension!(dd.dup)
|
|
627
|
+
end
|
|
628
|
+
end
|
|
467
629
|
temp_blueprint
|
|
468
630
|
end
|
|
469
631
|
|
|
470
|
-
#
|
|
632
|
+
# Helper for storing the project blueprint into a file as JSON.
|
|
471
633
|
#
|
|
472
|
-
# @param
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
634
|
+
# @param filename [String] Name of the file where the blueprint should be stored
|
|
635
|
+
def store_to_file(filename)
|
|
636
|
+
File.open(filename, 'w') do |f|
|
|
637
|
+
f << JSON.pretty_generate(to_hash)
|
|
638
|
+
end
|
|
476
639
|
end
|
|
477
640
|
|
|
478
641
|
# Returns title of a dataset. If not present it is generated from the name
|
|
479
642
|
#
|
|
480
643
|
# @return [String] a title
|
|
481
644
|
def title
|
|
482
|
-
Model.title(to_hash)
|
|
645
|
+
Model.title(to_hash) if to_hash[:title]
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
# Returns title of a dataset. If not present it is generated from the name
|
|
649
|
+
#
|
|
650
|
+
# @return [String] a title
|
|
651
|
+
def title=(a_title)
|
|
652
|
+
@data[:title] = a_title
|
|
483
653
|
end
|
|
484
654
|
|
|
485
655
|
# Returns Wire representation. This is used by our API to generate and
|
|
@@ -487,6 +657,7 @@ module GoodData
|
|
|
487
657
|
#
|
|
488
658
|
# @return [Hash] a title
|
|
489
659
|
def to_wire
|
|
660
|
+
validate
|
|
490
661
|
ToWire.to_wire(data)
|
|
491
662
|
end
|
|
492
663
|
|
|
@@ -495,20 +666,10 @@ module GoodData
|
|
|
495
666
|
#
|
|
496
667
|
# @return [Array<Hash>] a title
|
|
497
668
|
def to_manifest
|
|
669
|
+
validate
|
|
498
670
|
ToManifest.to_manifest(to_hash)
|
|
499
671
|
end
|
|
500
672
|
|
|
501
|
-
# Returns SLI manifest for one dataset. This is used by our API to allow
|
|
502
|
-
# loading data. The method is on project blueprint because you need
|
|
503
|
-
# acces to whole project to be able to generate references
|
|
504
|
-
#
|
|
505
|
-
# @param dataset [GoodData::Model::DatasetBlueprint | Hash | String] Dataset
|
|
506
|
-
# @param mode [String] Method of loading. FULL or INCREMENTAL
|
|
507
|
-
# @return [Array<Hash>] a title
|
|
508
|
-
def dataset_to_manifest(dataset, mode = 'FULL')
|
|
509
|
-
ToManifest.dataset_to_manifest(self, dataset, mode)
|
|
510
|
-
end
|
|
511
|
-
|
|
512
673
|
# Returns hash representation of blueprint
|
|
513
674
|
#
|
|
514
675
|
# @return [Hash] a title
|
|
@@ -516,12 +677,49 @@ module GoodData
|
|
|
516
677
|
@data
|
|
517
678
|
end
|
|
518
679
|
|
|
519
|
-
|
|
520
|
-
|
|
680
|
+
# Validate the blueprint in particular if all references reference existing datasets and valid fields inside them.
|
|
681
|
+
#
|
|
682
|
+
# @return [Array] array of errors
|
|
683
|
+
def validate_references
|
|
684
|
+
stuff = datasets(:all, include_date_dimensions: true).flat_map(&:references).select do |ref|
|
|
685
|
+
begin
|
|
686
|
+
ref.dataset
|
|
687
|
+
false
|
|
688
|
+
rescue RuntimeError
|
|
689
|
+
true
|
|
690
|
+
end
|
|
691
|
+
end
|
|
692
|
+
stuff.map { |r| { type: :bad_reference, reference: r.data, referencing_dataset: r.data[:dataset] } }
|
|
693
|
+
end
|
|
694
|
+
|
|
695
|
+
# Validate the blueprint and all its datasets return array of errors that are found.
|
|
696
|
+
#
|
|
697
|
+
# @return [Array] array of errors
|
|
698
|
+
def validate
|
|
699
|
+
errors = []
|
|
700
|
+
errors.concat validate_references
|
|
701
|
+
errors.concat datasets.reduce([]) { |a, e| a.concat(e.validate) }
|
|
702
|
+
errors.concat datasets.reduce([]) { |a, e| a.concat(e.validate_gd_data_type_errors) }
|
|
703
|
+
errors
|
|
704
|
+
rescue
|
|
705
|
+
raise GoodData::ValidationError
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
# Validate the blueprint and all its datasets and return true if model is valid. False otherwise.
|
|
709
|
+
#
|
|
710
|
+
# @return [Boolean] is model valid?
|
|
711
|
+
def valid?
|
|
712
|
+
validate.empty?
|
|
521
713
|
end
|
|
522
714
|
|
|
523
|
-
def
|
|
524
|
-
to_hash == other.to_hash
|
|
715
|
+
def ==(other)
|
|
716
|
+
# to_hash == other.to_hash
|
|
717
|
+
return false unless id == other.id
|
|
718
|
+
return false unless title == other.title
|
|
719
|
+
left = to_hash[:datasets].map { |d| d[:columns].to_set }.to_set
|
|
720
|
+
right = other.to_hash[:datasets].map { |d| d[:columns].to_set }.to_set
|
|
721
|
+
return false unless left == right
|
|
722
|
+
true
|
|
525
723
|
end
|
|
526
724
|
end
|
|
527
725
|
end
|