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,24 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
require 'gooddata'
|
|
3
|
+
|
|
4
|
+
describe GoodData::Model::AttributeBlueprintField do
|
|
5
|
+
|
|
6
|
+
before(:each) do
|
|
7
|
+
@model_view = MultiJson.load(File.read('./spec/data/wire_models/model_view.json'))
|
|
8
|
+
@blueprint = GoodData::Model::FromWire.from_wire(@model_view)
|
|
9
|
+
@dataset = @blueprint.datasets('dataset.account')
|
|
10
|
+
@attribute = @dataset.attributes('attr.account.region')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '#labels' do
|
|
14
|
+
it 'should return labels on dataset' do
|
|
15
|
+
expect(@attribute.labels.count).to eq 1
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe '#dataset' do
|
|
20
|
+
it 'should return dataset of the attribtue field' do
|
|
21
|
+
expect(@attribute.dataset_blueprint).to eq @dataset
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
require 'gooddata'
|
|
3
|
+
|
|
4
|
+
describe GoodData::Model::DatasetBlueprint do
|
|
5
|
+
|
|
6
|
+
before(:each) do
|
|
7
|
+
@model_view = MultiJson.load(File.read('./spec/data/wire_models/model_view.json'))
|
|
8
|
+
@blueprint = GoodData::Model::FromWire.from_wire(@model_view)
|
|
9
|
+
@dataset = @blueprint.datasets('dataset.opportunityanalysis')
|
|
10
|
+
@small_blueprint = GoodData::Model::ProjectBlueprint.build('my_bp') do |p|
|
|
11
|
+
p.add_dataset('dataset.countries') do |d|
|
|
12
|
+
d.add_anchor('attr.country')
|
|
13
|
+
d.add_label('label.country.name', reference: 'attr.country')
|
|
14
|
+
end
|
|
15
|
+
p.add_dataset('dataset.repos') do |d|
|
|
16
|
+
d.add_anchor('attr.repository')
|
|
17
|
+
d.add_label('label.repo.name', reference: 'attr.repository')
|
|
18
|
+
d.add_reference('dataset.countries')
|
|
19
|
+
end
|
|
20
|
+
p.add_dataset('dataset.devs') do |d|
|
|
21
|
+
d.add_anchor('attr.dev')
|
|
22
|
+
d.add_label('label.dev.name', reference: 'attr.dev')
|
|
23
|
+
end
|
|
24
|
+
p.add_dataset('dataset.commits') do |d|
|
|
25
|
+
d.add_anchor('attr.commits')
|
|
26
|
+
d.add_attribute('attr.quality')
|
|
27
|
+
d.add_label('label.quality', reference: 'attr.quality')
|
|
28
|
+
d.add_fact('more_numbers')
|
|
29
|
+
d.add_reference('dataset.repos')
|
|
30
|
+
d.add_reference('dataset.devs')
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe '#facts' do
|
|
36
|
+
it 'should return facts on dataset' do
|
|
37
|
+
expect(@dataset.facts.count).to eq 2
|
|
38
|
+
expect(@dataset.facts.map(&:id).to_set).to eq [
|
|
39
|
+
'fact.opportunityanalysis.buckets_to_display',
|
|
40
|
+
'fact.opportunityanalysis.month_fact'
|
|
41
|
+
].to_set
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'should be able to pick specific fact' do
|
|
45
|
+
expect(@dataset.facts('fact.opportunityanalysis.buckets_to_display').id).to eq 'fact.opportunityanalysis.buckets_to_display'
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe '#attributes' do
|
|
50
|
+
it 'should return attributes on dataset' do
|
|
51
|
+
expect(@dataset.attributes.count).to eq 2
|
|
52
|
+
expect(@dataset.attributes.map(&:id).to_set).to eq [
|
|
53
|
+
'attr.opportunityanalysis.month',
|
|
54
|
+
'attr.opportunityanalysis.cohorttype'
|
|
55
|
+
].to_set
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'should return attributes on dataset' do
|
|
59
|
+
expect(@dataset.attributes('attr.opportunityanalysis.cohorttype').id).to eq 'attr.opportunityanalysis.cohorttype'
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe '#labels' do
|
|
64
|
+
it 'should return labels on dataset' do
|
|
65
|
+
expect(@dataset.labels.count).to eq 4
|
|
66
|
+
expect(@dataset.labels.map(&:id).to_set).to eq [
|
|
67
|
+
'label.opportunityanalysis.month.monthsortingnew',
|
|
68
|
+
'label.opportunityanalysis.month',
|
|
69
|
+
'label.opportunityanalysis.cohorttype',
|
|
70
|
+
'label.opportunityanalysis.techoppanalysis'
|
|
71
|
+
].to_set
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe '#references' do
|
|
76
|
+
it 'should return references on dataset' do
|
|
77
|
+
expect(@dataset.references.count).to eq 2
|
|
78
|
+
expect(@dataset.references.map {|r| r.data[:dataset]}).to eq [
|
|
79
|
+
'dataset.opp_records',
|
|
80
|
+
'dataset.consolidatedmarketingstatus'
|
|
81
|
+
]
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe '#referenced_by' do
|
|
86
|
+
it 'should return datasets that are referencing this one' do
|
|
87
|
+
expect(@dataset.referenced_by).to eq []
|
|
88
|
+
dimension = @blueprint.datasets('dataset.opp_records')
|
|
89
|
+
expect(dimension.referenced_by.map(&:id)).to eq ['dataset.opportunityanalysis']
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
describe '#referencing' do
|
|
94
|
+
it 'should return datasets that are referenced by this one (the references in the dataset leads to those datasets)' do
|
|
95
|
+
expect(@dataset.referencing.map(&:id)).to eq ['dataset.opp_records', 'dataset.consolidatedmarketingstatus']
|
|
96
|
+
dimension = @blueprint.datasets('dataset.productline')
|
|
97
|
+
expect(dimension.referencing.map(&:id)).to be_empty
|
|
98
|
+
dimension = @blueprint.datasets('dataset.opp_records')
|
|
99
|
+
expect(dimension.referencing.map(&:id).count).to eq 28
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
describe '#breaks' do
|
|
104
|
+
it 'should return attributes that the dataset can break' do
|
|
105
|
+
expect(@small_blueprint.datasets('dataset.countries').breaks.map(&:id)).to eq ['attr.country', 'attr.repository', 'attr.quality']
|
|
106
|
+
expect(@small_blueprint.datasets('dataset.devs').breaks.map(&:id)).to eq ['attr.dev', 'attr.quality']
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
describe '#broken_by' do
|
|
111
|
+
it 'should return attributes that the dataset can be broken by' do
|
|
112
|
+
expect(@small_blueprint.datasets('dataset.commits').broken_by.map(&:id)).to eq ['attr.quality', 'attr.repository', 'attr.country', 'attr.dev']
|
|
113
|
+
expect(@small_blueprint.datasets('dataset.devs').broken_by.map(&:id)).to eq ['attr.dev']
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
require 'gooddata'
|
|
3
|
+
|
|
4
|
+
describe GoodData::Model::LabelBlueprintField do
|
|
5
|
+
|
|
6
|
+
before(:each) do
|
|
7
|
+
@model_view = MultiJson.load(File.read('./spec/data/wire_models/model_view.json'))
|
|
8
|
+
@blueprint = GoodData::Model::FromWire.from_wire(@model_view)
|
|
9
|
+
@dataset = @blueprint.datasets('dataset.opportunityanalysis')
|
|
10
|
+
@attribute = @dataset.attributes('attr.opportunityanalysis.month')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '#attribute' do
|
|
14
|
+
it 'should return attribute on label' do
|
|
15
|
+
labels = @attribute.labels
|
|
16
|
+
expect(labels.count).to eq 2
|
|
17
|
+
|
|
18
|
+
expect(labels[0].attribute).to eq @attribute
|
|
19
|
+
expect(labels[1].attribute).to eq @attribute
|
|
20
|
+
|
|
21
|
+
expect(labels[0].dataset_blueprint).to eq @dataset
|
|
22
|
+
expect(labels[1].dataset_blueprint).to eq @dataset
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe '#gd_type' do
|
|
27
|
+
it 'should return attribute on label' do
|
|
28
|
+
label = @blueprint.datasets('dataset.opportunityanalysis').labels('label.opportunityanalysis.techoppanalysis')
|
|
29
|
+
expect(label.gd_type).to eq 'GDC.text'
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe '#gd_datatype' do
|
|
34
|
+
it 'should return attribute on label' do
|
|
35
|
+
label = @blueprint.datasets('dataset.opportunityanalysis').labels('label.opportunityanalysis.techoppanalysis')
|
|
36
|
+
expect(label.gd_data_type).to eq 'VARCHAR(128)'
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
require 'gooddata'
|
|
3
|
+
|
|
4
|
+
describe GoodData::Model::ProjectBlueprint do
|
|
5
|
+
|
|
6
|
+
before(:each) do
|
|
7
|
+
@blueprint = GoodData::Model::ProjectBlueprint.from_json('./spec/data/blueprints/test_project_model_spec.json')
|
|
8
|
+
@invalid_blueprint = GoodData::Model::ProjectBlueprint.from_json('./spec/data/blueprints/invalid_blueprint.json')
|
|
9
|
+
@spec_blueprint = GoodData::Model::FromWire.from_wire(MultiJson.load(File.read('./spec/data/wire_models/model_view.json')))
|
|
10
|
+
@repos = @blueprint.find_dataset('dataset.repos')
|
|
11
|
+
@commits = @blueprint.find_dataset('dataset.commits')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe '#title' do
|
|
15
|
+
it "should return the title" do
|
|
16
|
+
expect(@blueprint.title).to eq "RubyGem Dev Week test"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe '#valid?' do
|
|
21
|
+
it 'valid blueprint should be marked as valid' do
|
|
22
|
+
expect(@blueprint.valid?).to eq true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'model should be invalid if it contains more than one anchor' do
|
|
26
|
+
bp = GoodData::Model::ProjectBlueprint.build("my_bp") do |p|
|
|
27
|
+
p.add_dataset("dataset.repos") do |d|
|
|
28
|
+
d.add_anchor("repo_id")
|
|
29
|
+
d.add_anchor("repo_id2")
|
|
30
|
+
d.add_fact("numbers")
|
|
31
|
+
d.add_attribute("name")
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
expect(bp.valid?).to be_falsey
|
|
35
|
+
errors = bp.validate
|
|
36
|
+
expect(errors.map {|x| x[:type]}.to_set).to eq [:attribute_without_label, :more_than_on_anchor].to_set
|
|
37
|
+
expect(errors.count).to eq 2
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'model should be invalid if it contains no anchor' do
|
|
41
|
+
bp = GoodData::Model::ProjectBlueprint.build("my_bp") do |p|
|
|
42
|
+
p.add_dataset("dataset.repos") do |d|
|
|
43
|
+
d.add_fact("numbers")
|
|
44
|
+
d.add_attribute("name")
|
|
45
|
+
d.add_label('some_label', reference: 'name')
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
expect(bp.valid?).to be_falsey
|
|
49
|
+
errors = bp.validate
|
|
50
|
+
expect(errors.first[:type]).to eq :no_anchor
|
|
51
|
+
expect(errors.count).to eq 1
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'model should be invalid if it has invalid gd data type' do
|
|
55
|
+
bp = GoodData::Model::ProjectBlueprint.build("my_bp") do |p|
|
|
56
|
+
p.add_dataset("dataset.repos") do |d|
|
|
57
|
+
d.add_anchor("attr.repository", label_id: 'label.repo.name', label_gd_data_type: "INTEGERX")
|
|
58
|
+
d.add_attribute("attr.attribute1", title: 'Some attribute')
|
|
59
|
+
d.add_label('label.attribute1.name', gd_data_type: "SOMEOTHER", reference: "attr.attribute1")
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
expect(bp.valid?).to be_falsey
|
|
63
|
+
errors = bp.validate
|
|
64
|
+
expect(errors.count).to eq 2
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'model should be valid if it has int specified as integer and default should be decimal' do
|
|
68
|
+
bp = GoodData::Model::ProjectBlueprint.build("my_bp") do |p|
|
|
69
|
+
p.add_dataset("dataset.repos") do |d|
|
|
70
|
+
d.add_anchor("attr.repository")
|
|
71
|
+
d.add_label('label.repository.name', reference: 'attr.repository')
|
|
72
|
+
d.add_attribute("attr.attribute1", title: 'Some attribute')
|
|
73
|
+
d.add_label('label.attribute1.name', reference: 'attr.attribute1')
|
|
74
|
+
d.add_fact('some_numbers', gd_data_type: 'INT')
|
|
75
|
+
d.add_fact('more_numbers')
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
bp.valid?.should == true
|
|
79
|
+
errors = bp.validate
|
|
80
|
+
expect(errors.count).to eq 0
|
|
81
|
+
facts = bp.to_wire[:diffRequest][:targetModel][:projectModel][:datasets].first[:dataset][:facts]
|
|
82
|
+
expect(facts[0][:fact][:dataType]).to eq 'INT'
|
|
83
|
+
expect(facts[1][:fact][:dataType]).to eq 'DECIMAL(12,2)'
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'invalid blueprint should be marked as invalid' do
|
|
87
|
+
expect(@invalid_blueprint.valid?).to eq false
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
describe '#validate' do
|
|
92
|
+
it 'valid blueprint should give you empty array of errors' do
|
|
93
|
+
expect(@blueprint.validate).to be_empty
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'invalid blueprint should give you list of violating references' do
|
|
97
|
+
errors = @invalid_blueprint.validate
|
|
98
|
+
expect(errors.size).to eq 1
|
|
99
|
+
expect(errors).to eq([{
|
|
100
|
+
:type=>:wrong_label_reference,
|
|
101
|
+
:label=>"some_label_id",
|
|
102
|
+
:wrong_reference=>"attr.repos.repo_id ERROR"
|
|
103
|
+
}])
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it 'invalid label is caught correctly' do
|
|
107
|
+
bp = GoodData::Model::ProjectBlueprint.build("my_bp") do |p|
|
|
108
|
+
p.add_dataset("dataset.repos") do |d|
|
|
109
|
+
d.add_anchor("attr.repository", label_id: 'label.repo.name')
|
|
110
|
+
d.add_attribute("attr.attribute1", title: 'Some attribute')
|
|
111
|
+
d.add_label('label.attribute1.name', reference: 'attr.attribute23123')
|
|
112
|
+
d.add_label('label.attribute1.ssn', reference: 'attr.attribute23123')
|
|
113
|
+
d.add_fact('some_numbers', gd_data_type: 'INT')
|
|
114
|
+
d.add_fact('more_numbers')
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
expect(bp.valid?).to be_falsey
|
|
118
|
+
errors = bp.validate
|
|
119
|
+
expect(errors.count).to eq 3
|
|
120
|
+
expect(errors).to eq [
|
|
121
|
+
{
|
|
122
|
+
:type=>:wrong_label_reference,
|
|
123
|
+
:label=>"label.attribute1.name",
|
|
124
|
+
:wrong_reference=>"attr.attribute23123"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
:type=>:wrong_label_reference,
|
|
128
|
+
:label=>"label.attribute1.ssn",
|
|
129
|
+
:wrong_reference=>"attr.attribute23123"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
:type=>:attribute_without_label,
|
|
133
|
+
:attribute=>"attr.attribute1"
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
describe '#remove_dataset!' do
|
|
140
|
+
it "should be able to remove dataset by name" do
|
|
141
|
+
expect(@blueprint.datasets.count).to eq 3
|
|
142
|
+
bp = @blueprint.remove_dataset!('dataset.repos')
|
|
143
|
+
expect(bp).to be_kind_of(GoodData::Model::ProjectBlueprint)
|
|
144
|
+
expect(@blueprint.datasets.count).to eq 2
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "should be able to remove dataset by reference" do
|
|
148
|
+
expect(@blueprint.datasets.count).to eq 3
|
|
149
|
+
dataset = @blueprint.find_dataset('dataset.repos')
|
|
150
|
+
bp = @blueprint.remove_dataset!(dataset)
|
|
151
|
+
expect(bp).to be_kind_of(GoodData::Model::ProjectBlueprint)
|
|
152
|
+
expect(@blueprint.datasets.count).to eq 2
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "should be able to remove dataset by name" do
|
|
156
|
+
expect(@blueprint.datasets.count).to eq 3
|
|
157
|
+
bp = GoodData::Model::ProjectBlueprint.remove_dataset!(@blueprint, 'dataset.repos')
|
|
158
|
+
expect(bp).to be_kind_of(Hash)
|
|
159
|
+
expect(@blueprint.datasets.count).to eq 2
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it "should be able to remove dataset by reference" do
|
|
163
|
+
expect(@blueprint.datasets.count).to eq 3
|
|
164
|
+
dataset = @blueprint.find_dataset('dataset.repos')
|
|
165
|
+
bp = GoodData::Model::ProjectBlueprint.remove_dataset!(@blueprint, dataset)
|
|
166
|
+
expect(bp).to be_kind_of(Hash)
|
|
167
|
+
expect(@blueprint.datasets.count).to eq 2
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
describe '#references' do
|
|
172
|
+
it 'references return empty array if there is no reference' do
|
|
173
|
+
refs = @blueprint.find_dataset('dataset.devs').references
|
|
174
|
+
expect(refs).to be_empty
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
describe '#find_dataset' do
|
|
179
|
+
it 'should be able to get dataset by identifier' do
|
|
180
|
+
ds = @blueprint.find_dataset('dataset.devs')
|
|
181
|
+
expect(ds.id).to eq 'dataset.devs'
|
|
182
|
+
expect(ds).to be_kind_of(GoodData::Model::DatasetBlueprint)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
it 'should throw an error if the dataset with a given name could not be found' do
|
|
186
|
+
expect { @blueprint.find_dataset('nonexisting_dataset') }.to raise_error
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it "should be pssible to find a dataset using dataset" do
|
|
190
|
+
ds = @blueprint.find_dataset('dataset.devs')
|
|
191
|
+
sds = @blueprint.find_dataset(ds)
|
|
192
|
+
expect(ds).to eq sds
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
describe '#to_blueprint' do
|
|
197
|
+
it "should be possible to create ProjectBlueprint from SchemaBuilder" do
|
|
198
|
+
builder = GoodData::Model::SchemaBuilder.create("stuff") do |d|
|
|
199
|
+
d.add_anchor("anchor_id")
|
|
200
|
+
d.add_attribute("id", title: "My Id")
|
|
201
|
+
d.add_label("label", reference: "id")
|
|
202
|
+
d.add_fact("amount", title: "Amount")
|
|
203
|
+
end
|
|
204
|
+
bp2 = builder.to_blueprint
|
|
205
|
+
expect(bp2.valid?).to eq true
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
it "should be possible to create ProjectBlueprint from SchemaBuilder" do
|
|
209
|
+
builder = GoodData::Model::SchemaBuilder.create("stuff") do |d|
|
|
210
|
+
d.add_anchor("anchor_id")
|
|
211
|
+
d.add_attribute("id", title: "My Id")
|
|
212
|
+
d.add_label("label", reference: "id")
|
|
213
|
+
d.add_fact("amount", title: "Amount")
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
bp1 = GoodData::Model::ProjectBlueprint.new(builder)
|
|
217
|
+
expect(bp1.valid?).to eq true
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
describe '#dataset?' do
|
|
222
|
+
it 'should be able to tell me if ceratain dataset by name is in the blueprint' do
|
|
223
|
+
expect(@blueprint.dataset?('dataset.devs')).to be_truthy
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
describe '#anchor?' do
|
|
228
|
+
it 'should tell you it has anchor when it does' do
|
|
229
|
+
expect(@repos.anchor?).to eq true
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
describe '#anchor' do
|
|
234
|
+
it 'should tell you anchor does have labels' do
|
|
235
|
+
expect(@commits.anchor.labels.count).to eq 0
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
it 'anchor should have labels' do
|
|
239
|
+
expect(@repos.anchor.labels.first.id).to eq 'some_label_id'
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
describe '#attributes' do
|
|
244
|
+
it 'attribute should have labels' do
|
|
245
|
+
expect(@repos.attributes.first.labels.first.id).to eq 'some_attr_label_id'
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it "should return attributes form all datasets" do
|
|
249
|
+
expect(@blueprint.attributes.count).to eq 1
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it 'should be able to grab attribute' do
|
|
253
|
+
expect(@repos.labels.size).to eq 2
|
|
254
|
+
expect(@repos.labels('some_attr_label_id').attribute).to eq @repos.attributes('some_attr_id')
|
|
255
|
+
expect(@repos.labels('some_label_id').attribute.id).to eq 'attr.repos.repo_id'
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
describe '#facts' do
|
|
260
|
+
it 'commits should have one fact' do
|
|
261
|
+
expect(@commits.facts.size).to eq 1
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
it 'commits should have one fact' do
|
|
265
|
+
expect(@repos.facts.size).to eq 0
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
it "should return facts form all datasets" do
|
|
269
|
+
expect(@blueprint.facts.count).to eq 1
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
describe '#labels' do
|
|
274
|
+
it 'Anchor on repos should have a label' do
|
|
275
|
+
expect(@repos.anchor.labels.size).to eq 1
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
it 'should not have a label for a dataset without anchor with label' do
|
|
279
|
+
expect(@commits.anchor.labels).to eq []
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
it "should return labels form all datasets" do
|
|
283
|
+
expect(@blueprint.labels.count).to eq 4
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
describe '#attributes_and_anchors' do
|
|
288
|
+
it "should return labels form all datasets" do
|
|
289
|
+
expect(@blueprint.attributes_and_anchors.count).to eq 4
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
describe '#merge' do
|
|
294
|
+
it "should be able to merge models without mutating the original" do
|
|
295
|
+
additional_blueprint = GoodData::Model::ProjectBlueprint.from_json("./spec/data/blueprints/additional_dataset_module.json")
|
|
296
|
+
expect(@blueprint.datasets.count).to eq 3
|
|
297
|
+
new_bp = @blueprint.merge(additional_blueprint)
|
|
298
|
+
expect(@blueprint.datasets.count).to eq 3
|
|
299
|
+
expect(new_bp.datasets.count).to eq 4
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
it "should perform merge in associative matter. Order should not matter." do
|
|
303
|
+
a = GoodData::Model::ProjectBlueprint.build("p") do |p|
|
|
304
|
+
p.add_date_dimension("updated_on")
|
|
305
|
+
p.add_dataset('stuff') do |d|
|
|
306
|
+
d.add_anchor('stuff_id')
|
|
307
|
+
d.add_label('name', reference: 'stuff_id')
|
|
308
|
+
d.add_date('updated_on')
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
b = GoodData::Model::ProjectBlueprint.build("p") do |p|
|
|
312
|
+
p.add_date_dimension("created_on")
|
|
313
|
+
p.add_dataset('stuff') do |d|
|
|
314
|
+
d.add_attribute('attr_id')
|
|
315
|
+
d.add_label('attr_name', reference: 'attr_id')
|
|
316
|
+
d.add_date('created_on')
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
# those two are the same. Notice that we have made the titles the same
|
|
320
|
+
# Merging titles is not associative
|
|
321
|
+
a_b = a.merge(b)
|
|
322
|
+
b_a = b.merge(a)
|
|
323
|
+
expect(a_b.valid?).to eq true
|
|
324
|
+
expect(b_a.valid?).to eq true
|
|
325
|
+
expect(b_a).to eq a_b
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
it "should perform merge in associative matter. Order should not matter." do
|
|
329
|
+
a = GoodData::Model::ProjectBlueprint.build("p") do |p|
|
|
330
|
+
p.add_date_dimension("updated_on")
|
|
331
|
+
p.add_dataset('stuff') do |d|
|
|
332
|
+
d.add_anchor('stuff_id')
|
|
333
|
+
d.add_label('name', reference: 'stuff_id')
|
|
334
|
+
d.add_date('updated_on')
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
b = GoodData::Model::ProjectBlueprint.build("p") do |p|
|
|
338
|
+
p.add_date_dimension("created_on")
|
|
339
|
+
p.add_dataset('stuff') do |d|
|
|
340
|
+
d.add_attribute('attr_id')
|
|
341
|
+
d.add_label('attr_name', reference: 'attr_id')
|
|
342
|
+
d.add_date('created_on')
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
# those two are the same. Notice that we have made the titles the same
|
|
346
|
+
# Merging titles is not associative
|
|
347
|
+
a_b = a.merge(b)
|
|
348
|
+
b_a = b.merge(a)
|
|
349
|
+
expect(a_b.valid?).to eq true
|
|
350
|
+
expect(b_a.valid?).to eq true
|
|
351
|
+
expect(b_a).to eq a_b
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
it "should fail if unable to merge date dimensions (they are different)." do
|
|
355
|
+
a = GoodData::Model::ProjectBlueprint.build("p") do |p|
|
|
356
|
+
p.add_date_dimension("created_on", title: 'title A')
|
|
357
|
+
p.add_dataset('stuff') do |d|
|
|
358
|
+
d.add_anchor('stuff_id')
|
|
359
|
+
d.add_label('name', reference: 'stuff_id')
|
|
360
|
+
d.add_date('created_on')
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
b = GoodData::Model::ProjectBlueprint.build("p") do |p|
|
|
364
|
+
p.add_date_dimension("created_on", title: 'title B')
|
|
365
|
+
p.add_dataset('stuff') do |d|
|
|
366
|
+
d.add_attribute('attr_id')
|
|
367
|
+
d.add_label('attr_name', reference: 'attr_id')
|
|
368
|
+
d.add_date('created_on')
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
expect {
|
|
372
|
+
c = a.merge(b)
|
|
373
|
+
}.to raise_exception 'Unable to merge date dimensions created_on with defintion {:type=>:date_dimension, :urn=>nil, :id=>"created_on", :title=>"title B"} with {:type=>:date_dimension, :urn=>nil, :id=>"created_on", :title=>"title A"}'
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
describe '#merge!' do
|
|
378
|
+
it "should be able to merge models" do
|
|
379
|
+
additional_blueprint = GoodData::Model::ProjectBlueprint.from_json("./spec/data/blueprints/additional_dataset_module.json")
|
|
380
|
+
expect(@blueprint.datasets.count).to eq 3
|
|
381
|
+
@blueprint.merge!(additional_blueprint)
|
|
382
|
+
expect(@blueprint.datasets.count).to eq 4
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
it "should be able to add datasets on the fly" do
|
|
387
|
+
builder = GoodData::Model::SchemaBuilder.new("stuff") do |d|
|
|
388
|
+
d.add_attribute("id", title: "My Id")
|
|
389
|
+
d.add_fact("amount", title: "Amount")
|
|
390
|
+
end
|
|
391
|
+
dataset = builder.to_blueprint
|
|
392
|
+
expect(@blueprint.datasets.count).to eq 3
|
|
393
|
+
@blueprint.add_dataset!(dataset)
|
|
394
|
+
expect(@blueprint.datasets.count).to eq 4
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
it "should be able to serialize itself to a hash" do
|
|
400
|
+
ser = @blueprint.to_hash
|
|
401
|
+
ser.is_a?(Hash)
|
|
402
|
+
expect(ser.keys).to eq [:title, :datasets, :date_dimensions]
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
it "should be able to tell you whether a dataset is referencing any others including date dimensions" do
|
|
406
|
+
d = @blueprint.datasets('dataset.commits')
|
|
407
|
+
referenced_datasets = @blueprint.referenced_by(d)
|
|
408
|
+
expect(referenced_datasets.count).to eq 3
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
it "should be able to find star centers - datasets that are not referenced by any other - these are typical fact tables" do
|
|
412
|
+
centers = @blueprint.find_star_centers
|
|
413
|
+
expect(centers.count).to eq 1
|
|
414
|
+
expect(centers.first.id).to eq 'dataset.commits'
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
it "should be able to return all attributes or anchors that can break metrics computed in the context of given dataset" do
|
|
418
|
+
commits = @blueprint.datasets('dataset.commits')
|
|
419
|
+
expect(commits.broken_by.count).to eq 3
|
|
420
|
+
expect(commits.broken_by.map(&:id)).to eq ["attr.devs.dev_id", "some_attr_id", "attr.repos.repo_id"]
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
it 'blueprint can be set without date reference and default format is set' do
|
|
424
|
+
bp = GoodData::Model::ProjectBlueprint.build("my_bp") do |p|
|
|
425
|
+
p.add_date_dimension("committed_on")
|
|
426
|
+
|
|
427
|
+
p.add_dataset("dataset.repos") do |d|
|
|
428
|
+
d.add_anchor("attr.repository")
|
|
429
|
+
d.add_label('label.repo.name')
|
|
430
|
+
d.add_attribute("attr.attribute1", title: 'Some attribute')
|
|
431
|
+
d.add_label('label.attribute1.name', reference: 'attr.attribute1')
|
|
432
|
+
d.add_label('label.attribute1.ssn', reference: 'attr.attribute1')
|
|
433
|
+
d.add_fact('some_numbers', gd_data_type: 'INT')
|
|
434
|
+
d.add_fact('more_numbers')
|
|
435
|
+
d.add_date('opportunity_comitted', dataset: 'committed_on')
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
expect(bp.datasets.flat_map { |d| d.find_columns_by_type(:date) }.map { |a| a.format }).to eq [GoodData::Model::DEFAULT_DATE_FORMAT]
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
it 'blueprint can be set with explicit date' do
|
|
442
|
+
bp = GoodData::Model::ProjectBlueprint.build("my_bp") do |p|
|
|
443
|
+
p.add_date_dimension("committed_on")
|
|
444
|
+
|
|
445
|
+
p.add_dataset("dataset.repos") do |d|
|
|
446
|
+
d.add_anchor("attr.repository", label_id: 'label.repo.name')
|
|
447
|
+
d.add_attribute("attr.attribute1")
|
|
448
|
+
d.add_label('label.attribute1.name', title: 'Some attribute', reference: 'attr.attribute1')
|
|
449
|
+
d.add_label('label.attribute1.ssn', reference: 'attr.attribute1')
|
|
450
|
+
d.add_fact('some_numbers', gd_data_type: 'INT')
|
|
451
|
+
d.add_fact('more_numbers')
|
|
452
|
+
d.add_date('opportunity_comitted', dataset: 'committed_on', format: 'yyyy/MM/dd')
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
expect(bp.valid?).to be_truthy
|
|
456
|
+
expect(bp.datasets.flat_map { |d| d.find_columns_by_type(:date) }.map { |a| a.format }).to eq ['yyyy/MM/dd']
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
describe '#remove' do
|
|
460
|
+
it 'can remove the anchor' do
|
|
461
|
+
bp = GoodData::Model::ProjectBlueprint.build("my_bp") do |p|
|
|
462
|
+
p.add_dataset("dataset.repos") do |d|
|
|
463
|
+
d.add_anchor("attr.repository", label_id: 'label.repo.name')
|
|
464
|
+
d.add_label('label.repository.name', title: 'Some attribute', reference: 'attr.repository')
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
expect(bp.datasets('dataset.repos').anchor.labels.count).to eq 1
|
|
468
|
+
bp.datasets('dataset.repos').anchor.remove!
|
|
469
|
+
expect(bp.datasets('dataset.repos').anchor.labels.count).to eq 0
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
describe '#move!' do
|
|
474
|
+
it 'can move attribute around' do
|
|
475
|
+
expect(@blueprint.datasets('dataset.repos').fields.count).to eq 4
|
|
476
|
+
expect(@blueprint.datasets('dataset.commits').fields.count).to eq 5
|
|
477
|
+
attr_before = @blueprint.datasets('dataset.repos').attributes('some_attr_id')
|
|
478
|
+
expect(attr_before).to_not be_nil
|
|
479
|
+
expect(@blueprint.datasets('dataset.commits').attributes('some_attr_id')).to be_nil
|
|
480
|
+
expect(attr_before.labels.first.dataset_blueprint.id).to eq 'dataset.repos'
|
|
481
|
+
@blueprint.move!('some_attr_id', 'dataset.repos', 'dataset.commits')
|
|
482
|
+
|
|
483
|
+
attr_after = @blueprint.datasets('dataset.commits').attributes('some_attr_id')
|
|
484
|
+
|
|
485
|
+
expect(@blueprint.datasets('dataset.repos').fields.count).to eq 2
|
|
486
|
+
expect(@blueprint.datasets('dataset.commits').fields.count).to eq 7
|
|
487
|
+
expect(@blueprint.datasets('dataset.repos').attributes('some_attr_id')).to be_nil
|
|
488
|
+
expect(attr_after).to_not be_nil
|
|
489
|
+
expect(attr_after.labels.first.dataset_blueprint.id).to eq 'dataset.commits'
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
it 'can move fact around' do
|
|
493
|
+
@blueprint.move!('fact.commits.lines_changed', 'dataset.commits', 'dataset.repos')
|
|
494
|
+
expect(@blueprint.datasets('dataset.commits').facts.count).to eq 0
|
|
495
|
+
expect(@blueprint.datasets('dataset.repos').facts.count).to eq 1
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
it 'crashes gracefully when nonexistent field is being moved' do
|
|
499
|
+
expect {
|
|
500
|
+
@blueprint.move!('nonexistent_field', 'dataset.commits', 'dataset.repos')
|
|
501
|
+
}.to raise_exception 'Column nonexistent_field cannot be found in dataset dataset.commits'
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
it 'crashes gracefully when datasets does not exist' do
|
|
505
|
+
expect {
|
|
506
|
+
@blueprint.move!('nonexistent_field', 'dataset.A', 'dataset.repos')
|
|
507
|
+
}.to raise_exception 'Dataset "dataset.A" could not be found'
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
it 'crashes gracefully when datasets does not exist' do
|
|
511
|
+
expect {
|
|
512
|
+
@blueprint.move!('nonexistent_field', 'dataset.commits', 'dataset.B')
|
|
513
|
+
}.to raise_exception 'Dataset "dataset.B" could not be found'
|
|
514
|
+
end
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
it 'should be able to refactor facts from attributes' do
|
|
518
|
+
blueprint = GoodData::Model::ProjectBlueprint.build("my_bp") do |p|
|
|
519
|
+
p.add_dataset('opportunities') do |d|
|
|
520
|
+
d.add_anchor('opportunities.id')
|
|
521
|
+
d.add_fact('opportunities.age')
|
|
522
|
+
d.add_fact('opportunities.amount')
|
|
523
|
+
d.add_attribute('opportunities.name')
|
|
524
|
+
d.add_label('label.opportunities.name', reference: 'opportunities.name')
|
|
525
|
+
d.add_attribute('opportunities.region')
|
|
526
|
+
d.add_label('label.opportunities.region', reference: 'opportunities.region')
|
|
527
|
+
d.add_reference('user_id', dataset: 'users')
|
|
528
|
+
d.add_reference('account_id', dataset: 'accounts')
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
p.add_dataset('users') do |d|
|
|
532
|
+
d.add_anchor('users.id')
|
|
533
|
+
d.add_attribute('users.name')
|
|
534
|
+
d.add_label('label.users.name', reference: 'users.name')
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
p.add_dataset('accounts') do |d|
|
|
538
|
+
d.add_anchor('accounts.id')
|
|
539
|
+
d.add_attribute('accounts.name')
|
|
540
|
+
d.add_label('label.accounts.region', reference: 'accounts.name')
|
|
541
|
+
end
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
refactored = GoodData::Model::ProjectBlueprint.build("my_bp") do |p|
|
|
545
|
+
p.add_dataset('opportunities') do |d|
|
|
546
|
+
d.add_anchor('opportunities.id')
|
|
547
|
+
d.add_fact('opportunities.age')
|
|
548
|
+
d.add_fact('opportunities.amount')
|
|
549
|
+
d.add_reference('user_id', dataset: 'users')
|
|
550
|
+
d.add_reference('accounts')
|
|
551
|
+
d.add_reference('accounts')
|
|
552
|
+
d.add_reference('opportunities_dim')
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
p.add_dataset('opportunities_dim') do |d|
|
|
556
|
+
d.add_anchor('vymysli_id')
|
|
557
|
+
d.add_label('label.vymysli_id', reference: 'vymysli_id')
|
|
558
|
+
|
|
559
|
+
d.add_attribute('opportunities.name')
|
|
560
|
+
d.add_label('label.opportunities.name', reference: 'opportunities.name')
|
|
561
|
+
d.add_attribute('opportunities.region')
|
|
562
|
+
d.add_label('label.opportunities.region', reference: 'opportunities.region')
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
p.add_dataset('users') do |d|
|
|
566
|
+
d.add_anchor('users.id')
|
|
567
|
+
d.add_attribute('users.name')
|
|
568
|
+
d.add_label('label.users.name', reference: 'users.name')
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
p.add_dataset('accounts') do |d|
|
|
572
|
+
d.add_anchor('accounts.id')
|
|
573
|
+
d.add_attribute('accounts.name')
|
|
574
|
+
d.add_label('label.accounts.region', reference: 'accounts.name')
|
|
575
|
+
end
|
|
576
|
+
end
|
|
577
|
+
expect(blueprint.refactor_split_df('opportunities')).to eq refactored
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
it 'should be able to refactor facts as a split into 2 datasets' do
|
|
581
|
+
blueprint = GoodData::Model::ProjectBlueprint.build("my_bp") do |p|
|
|
582
|
+
p.add_dataset('opportunities') do |d|
|
|
583
|
+
d.add_anchor('opportunities.id')
|
|
584
|
+
d.add_fact('opportunities.age')
|
|
585
|
+
d.add_fact('opportunities.amount')
|
|
586
|
+
d.add_attribute('opportunities.name')
|
|
587
|
+
d.add_label('label.opportunities.name', reference: 'opportunities.name')
|
|
588
|
+
d.add_attribute('opportunities.region')
|
|
589
|
+
d.add_label('label.opportunities.region', reference: 'opportunities.region')
|
|
590
|
+
d.add_reference('user_id', dataset: 'users')
|
|
591
|
+
d.add_reference('account_id', dataset: 'accounts')
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
p.add_dataset('users') do |d|
|
|
595
|
+
d.add_anchor('users.id')
|
|
596
|
+
d.add_attribute('users.name')
|
|
597
|
+
d.add_label('label.users.name', reference: 'users.name')
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
p.add_dataset('accounts') do |d|
|
|
601
|
+
d.add_anchor('accounts.id')
|
|
602
|
+
d.add_attribute('accounts.name')
|
|
603
|
+
d.add_label('label.accounts.region', reference: 'accounts.name')
|
|
604
|
+
end
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
refactored = GoodData::Model::ProjectBlueprint.build("my_bp") do |p|
|
|
608
|
+
p.add_dataset('opportunities') do |d|
|
|
609
|
+
d.add_anchor('opportunities.id')
|
|
610
|
+
d.add_fact('opportunities.amount')
|
|
611
|
+
d.add_attribute('opportunities.name')
|
|
612
|
+
d.add_label('label.opportunities.name', reference: 'opportunities.name')
|
|
613
|
+
d.add_attribute('opportunities.region')
|
|
614
|
+
d.add_label('label.opportunities.region', reference: 'opportunities.region')
|
|
615
|
+
d.add_reference('user_id', dataset: 'users')
|
|
616
|
+
d.add_reference('account_id', dataset: 'accounts')
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
p.add_dataset('users') do |d|
|
|
620
|
+
d.add_anchor('users.id')
|
|
621
|
+
d.add_attribute('users.name')
|
|
622
|
+
d.add_label('label.users.name', reference: 'users.name')
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
p.add_dataset('accounts') do |d|
|
|
626
|
+
d.add_anchor('accounts.id')
|
|
627
|
+
d.add_attribute('accounts.name')
|
|
628
|
+
d.add_label('label.accounts.region', reference: 'accounts.name')
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
p.add_dataset('opportunities_age_fact') do |d|
|
|
632
|
+
d.add_anchor('opportunities_age_fact.id')
|
|
633
|
+
d.add_fact('opportunities.age')
|
|
634
|
+
d.add_reference('user_id', dataset: 'users')
|
|
635
|
+
d.add_reference('account_id', dataset: 'accounts')
|
|
636
|
+
end
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
col_names = ['opportunities.age']
|
|
640
|
+
# that should be possible to express with #refactor_split_facts
|
|
641
|
+
expect(blueprint.refactor_split_facts('opportunities', col_names, 'opportunities_age_fact')).to eq refactored
|
|
642
|
+
end
|
|
643
|
+
end
|