masamune 0.17.4 → 0.17.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/masamune/tasks/dump_thor.rb +2 -0
- data/lib/masamune/transform/define_schema.rb +3 -3
- data/lib/masamune/transform/define_table.rb +29 -2
- data/lib/masamune/transform/load_dimension.rb +1 -1
- data/lib/masamune/transform/load_fact.rb +1 -1
- data/lib/masamune/transform/postgres/define_table.psql.erb +0 -4
- data/lib/masamune/transform/postgres/define_table.rb +1 -5
- data/lib/masamune/version.rb +1 -1
- data/spec/masamune/tasks/dump_thor_spec.rb +10 -0
- data/spec/masamune/transform/define_schema_spec.rb +23 -1
- data/spec/masamune/transform/define_table.dimension_spec.rb +68 -1
- data/spec/masamune/transform/define_table.fact_spec.rb +14 -13
- data/spec/masamune/transform/define_table.table_spec.rb +35 -1
- data/spec/masamune/transform/load_dimension_spec.rb +3 -3
- data/spec/masamune/transform/load_fact_spec.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3067d46a85020fb673687d897550d3590dd34e15
|
4
|
+
data.tar.gz: 8f3a034427ba96b5209434cb997d1eb7c313e91d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a061bfc2c774867f1430534b0974f7d76ee4f8f5eeba0d6a796d698c7779b7f2c19d95996a526d1b915b183813c30f160a159cb96505079af9b205e2805a8631
|
7
|
+
data.tar.gz: 21f0072fa6b117d8525302064458c3ce987ede2947ef2138a45f0840cb46701b767e6d86cf12812b01c420f0c1097de8f9db66846571b5903acccff8c5f58c1a
|
@@ -37,6 +37,7 @@ module Masamune::Tasks
|
|
37
37
|
desc 'dump', 'Dump schema'
|
38
38
|
method_option :type, :enum => ['psql', 'hql'], :desc => 'Schema type', :default => 'psql'
|
39
39
|
method_option :section, :enum => ['pre', 'post', 'all'], :desc => 'Schema section', :default => 'all'
|
40
|
+
method_option :exclude, :type => :array, :desc => 'Exclude tables matching globs', :default => []
|
40
41
|
def dump_exec
|
41
42
|
print_catalog
|
42
43
|
exit
|
@@ -56,6 +57,7 @@ module Masamune::Tasks
|
|
56
57
|
|
57
58
|
def define_schema_options
|
58
59
|
{
|
60
|
+
exclude: options[:exclude],
|
59
61
|
section: options[:section].to_sym,
|
60
62
|
start_date: start_date,
|
61
63
|
stop_date: stop_date
|
@@ -35,13 +35,13 @@ module Masamune::Transform
|
|
35
35
|
operators += context.extra(:pre)
|
36
36
|
|
37
37
|
context.dimensions.each do |_, dimension|
|
38
|
-
operators << define_table(dimension,
|
38
|
+
operators << define_table(dimension, options)
|
39
39
|
end
|
40
40
|
|
41
41
|
context.facts.each do |_, fact|
|
42
|
-
operators << define_table(fact,
|
42
|
+
operators << define_table(fact, options)
|
43
43
|
fact.partition_tables(options[:start_date], options[:stop_date]) do |fact_partition_table|
|
44
|
-
operators << define_table(fact_partition_table,
|
44
|
+
operators << define_table(fact_partition_table, options)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -24,11 +24,38 @@ module Masamune::Transform
|
|
24
24
|
module DefineTable
|
25
25
|
extend ActiveSupport::Concern
|
26
26
|
|
27
|
-
def define_table(target,
|
27
|
+
def define_table(target, options = {})
|
28
28
|
return if target.implicit
|
29
|
-
|
29
|
+
return if exclude_table?(target, options)
|
30
|
+
child_tables = target.children.map { |child| define_table(child, options.except(:files)) }
|
31
|
+
Operator.new(*child_tables, __method__, target: target, files: options[:files], section: options[:section]).tap do |operator|
|
30
32
|
logger.debug("#{target.id}\n" + operator.to_s) if target.debug
|
31
33
|
end
|
32
34
|
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def exclude_table?(table, options = {})
|
39
|
+
exclude_matchers(options[:exclude]).any? { |matcher| matcher =~ table.name }
|
40
|
+
end
|
41
|
+
|
42
|
+
def exclude_matchers(exclude)
|
43
|
+
Array.wrap(exclude).map do |input|
|
44
|
+
case input
|
45
|
+
when String
|
46
|
+
glob_to_regexp(input)
|
47
|
+
when Regexp
|
48
|
+
input
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def glob_to_regexp(input)
|
54
|
+
if input.include?('*')
|
55
|
+
%r|\A#{Regexp.escape(input).gsub('\\*', '.*?')}|
|
56
|
+
else
|
57
|
+
/\A#{Regexp.escape(input)}\z/
|
58
|
+
end
|
59
|
+
end
|
33
60
|
end
|
34
61
|
end
|
@@ -38,7 +38,7 @@ module Masamune::Transform
|
|
38
38
|
target = target.type == :four ? target.ledger_table : target
|
39
39
|
source = source.stage_table(suffix: 'file', table: target, inherit: false)
|
40
40
|
Operator.new \
|
41
|
-
define_table(source, files),
|
41
|
+
define_table(source, files: files),
|
42
42
|
insert_reference_values(source, target),
|
43
43
|
stage_dimension(source, target),
|
44
44
|
bulk_upsert(target.stage_table, target)
|
@@ -37,7 +37,7 @@ module Masamune::Transform
|
|
37
37
|
def load_fact(files, source, target, date)
|
38
38
|
source = source.stage_table(suffix: 'file', table: target, inherit: false)
|
39
39
|
Operator.new \
|
40
|
-
define_table(source, files),
|
40
|
+
define_table(source, files: files),
|
41
41
|
insert_reference_values(source, target),
|
42
42
|
stage_fact(source, target, date)
|
43
43
|
end
|
@@ -24,10 +24,6 @@
|
|
24
24
|
files ||= []
|
25
25
|
%>
|
26
26
|
|
27
|
-
<%- target.children.each do |child| -%>
|
28
|
-
<%= render 'define_table.psql.erb', target: child, **locals.except(:target, :files) %>
|
29
|
-
<%- end -%>
|
30
|
-
|
31
27
|
<%- if helper.define_types? %>
|
32
28
|
<%- target.enum_columns.each do |_, column| -%>
|
33
29
|
DO $$ BEGIN
|
@@ -90,7 +90,7 @@ module Masamune::Transform::Postgres
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def insert_rows?
|
93
|
-
!post_section?
|
93
|
+
!pre_section? && !post_section?
|
94
94
|
end
|
95
95
|
|
96
96
|
def load_files?
|
@@ -118,10 +118,6 @@ module Masamune::Transform::Postgres
|
|
118
118
|
end
|
119
119
|
|
120
120
|
class TargetPresenter < SimpleDelegator
|
121
|
-
def children
|
122
|
-
super.map { |child| self.class.new(child) }
|
123
|
-
end
|
124
|
-
|
125
121
|
def inherited?
|
126
122
|
type == :fact && inheritance_constraints
|
127
123
|
end
|
data/lib/masamune/version.rb
CHANGED
@@ -67,6 +67,16 @@ describe Masamune::Tasks::DumpThor do
|
|
67
67
|
it_behaves_like 'raises Thor::MalformattedArgumentError', %q{Expected '--section' to be one of pre, post, all; got unknown}
|
68
68
|
end
|
69
69
|
|
70
|
+
context %q{with --exclude='.*dimension'} do
|
71
|
+
let(:options) { [%q{--exclude='.*dimension'}] }
|
72
|
+
it_behaves_like 'executes with success'
|
73
|
+
end
|
74
|
+
|
75
|
+
context %q{with --exclude='.*dimension' '.*fact'} do
|
76
|
+
let(:options) { [%q{--exclude='.*dimension' '.*fact'}] }
|
77
|
+
it_behaves_like 'executes with success'
|
78
|
+
end
|
79
|
+
|
70
80
|
context 'with --start=yesterday' do
|
71
81
|
let(:options) { ['--start=yesterday'] }
|
72
82
|
it_behaves_like 'executes with success'
|
@@ -66,7 +66,7 @@ describe Masamune::Transform::DefineSchema do
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
context '
|
69
|
+
context 'with start_date and stop_date' do
|
70
70
|
subject(:result) { transform.define_schema(catalog, :postgres, start_date: Date.civil(2015, 01, 01), stop_date: Date.civil(2015, 03, 15)).to_s }
|
71
71
|
|
72
72
|
it 'should render combined template' do
|
@@ -80,6 +80,28 @@ describe Masamune::Transform::DefineSchema do
|
|
80
80
|
transform.define_table(catalog.postgres.facts['visits'].partition_table(Date.civil(2015, 03, 01)))
|
81
81
|
end
|
82
82
|
end
|
83
|
+
|
84
|
+
context 'with exclude Regexp' do
|
85
|
+
subject(:result) { transform.define_schema(catalog, :postgres, exclude: /.*dimension/).to_s }
|
86
|
+
|
87
|
+
it 'should render combined template' do
|
88
|
+
is_expected.to eq Masamune::Template.combine \
|
89
|
+
Masamune::Transform::Operator.new('define_schema', source: catalog.postgres),
|
90
|
+
transform.define_table(catalog.postgres.dimensions['user_account_state']),
|
91
|
+
transform.define_table(catalog.postgres.facts['visits'])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'with exclude glob' do
|
96
|
+
subject(:result) { transform.define_schema(catalog, :postgres, exclude: '*dimension').to_s }
|
97
|
+
|
98
|
+
it 'should render combined template' do
|
99
|
+
is_expected.to eq Masamune::Template.combine \
|
100
|
+
Masamune::Transform::Operator.new('define_schema', source: catalog.postgres),
|
101
|
+
transform.define_table(catalog.postgres.dimensions['user_account_state']),
|
102
|
+
transform.define_table(catalog.postgres.facts['visits'])
|
103
|
+
end
|
104
|
+
end
|
83
105
|
end
|
84
106
|
|
85
107
|
context 'for hive schema' do
|
@@ -21,7 +21,8 @@
|
|
21
21
|
# THE SOFTWARE.
|
22
22
|
|
23
23
|
describe Masamune::Transform::DefineTable do
|
24
|
-
|
24
|
+
let(:options) { {} }
|
25
|
+
subject { transform.define_table(table, options).to_s }
|
25
26
|
|
26
27
|
context 'for hive implicit dimension' do
|
27
28
|
before do
|
@@ -415,4 +416,70 @@ describe Masamune::Transform::DefineTable do
|
|
415
416
|
EOS
|
416
417
|
end
|
417
418
|
end
|
419
|
+
|
420
|
+
context 'for postgres dimension type: four with exclude /.*ledger/' do
|
421
|
+
before do
|
422
|
+
catalog.schema :postgres do
|
423
|
+
dimension 'user', type: :four do
|
424
|
+
column 'tenant_id', natural_key: true
|
425
|
+
column 'user_id', natural_key: true
|
426
|
+
column 'preferences', type: :key_value, null: true
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
let(:options) { { exclude: /.*ledger\z/ } }
|
432
|
+
let(:table) { catalog.postgres.user_dimension }
|
433
|
+
|
434
|
+
it 'should render table template' do
|
435
|
+
is_expected.to eq <<-EOS.strip_heredoc
|
436
|
+
CREATE TABLE IF NOT EXISTS user_dimension
|
437
|
+
(
|
438
|
+
id SERIAL,
|
439
|
+
tenant_id INTEGER NOT NULL,
|
440
|
+
user_id INTEGER NOT NULL,
|
441
|
+
preferences HSTORE,
|
442
|
+
start_at TIMESTAMP NOT NULL DEFAULT TO_TIMESTAMP(0),
|
443
|
+
end_at TIMESTAMP,
|
444
|
+
version INTEGER DEFAULT 1,
|
445
|
+
last_modified_at TIMESTAMP NOT NULL DEFAULT NOW()
|
446
|
+
);
|
447
|
+
|
448
|
+
DO $$ BEGIN
|
449
|
+
IF NOT EXISTS (SELECT 1 FROM pg_class c WHERE c.relname = 'user_dimension_pkey') THEN
|
450
|
+
ALTER TABLE user_dimension ADD PRIMARY KEY (id);
|
451
|
+
END IF; END $$;
|
452
|
+
|
453
|
+
DO $$ BEGIN
|
454
|
+
IF NOT EXISTS (SELECT 1 FROM pg_class c WHERE c.relname = 'user_dimension_e6c3d91_key') THEN
|
455
|
+
ALTER TABLE user_dimension ADD CONSTRAINT user_dimension_e6c3d91_key UNIQUE(tenant_id, user_id, start_at);
|
456
|
+
END IF; END $$;
|
457
|
+
|
458
|
+
DO $$ BEGIN
|
459
|
+
IF NOT EXISTS (SELECT 1 FROM pg_class c WHERE c.relname = 'user_dimension_2c8e908_index') THEN
|
460
|
+
CREATE INDEX user_dimension_2c8e908_index ON user_dimension (end_at);
|
461
|
+
END IF; END $$;
|
462
|
+
|
463
|
+
DO $$ BEGIN
|
464
|
+
IF NOT EXISTS (SELECT 1 FROM pg_class c WHERE c.relname = 'user_dimension_23563d3_index') THEN
|
465
|
+
CREATE INDEX user_dimension_23563d3_index ON user_dimension (start_at);
|
466
|
+
END IF; END $$;
|
467
|
+
|
468
|
+
DO $$ BEGIN
|
469
|
+
IF NOT EXISTS (SELECT 1 FROM pg_class c WHERE c.relname = 'user_dimension_3854361_index') THEN
|
470
|
+
CREATE INDEX user_dimension_3854361_index ON user_dimension (tenant_id);
|
471
|
+
END IF; END $$;
|
472
|
+
|
473
|
+
DO $$ BEGIN
|
474
|
+
IF NOT EXISTS (SELECT 1 FROM pg_class c WHERE c.relname = 'user_dimension_e8701ad_index') THEN
|
475
|
+
CREATE INDEX user_dimension_e8701ad_index ON user_dimension (user_id);
|
476
|
+
END IF; END $$;
|
477
|
+
|
478
|
+
DO $$ BEGIN
|
479
|
+
IF NOT EXISTS (SELECT 1 FROM pg_class c WHERE c.relname = 'user_dimension_e6c3d91_index') THEN
|
480
|
+
CREATE UNIQUE INDEX user_dimension_e6c3d91_index ON user_dimension (tenant_id, user_id, start_at);
|
481
|
+
END IF; END $$;
|
482
|
+
EOS
|
483
|
+
end
|
484
|
+
end
|
418
485
|
end
|
@@ -122,11 +122,12 @@ describe Masamune::Transform::DefineTable do
|
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
125
|
+
let(:options) { {} }
|
126
|
+
subject(:result) { transform.define_table(target, options).to_s }
|
127
|
+
|
125
128
|
context 'for postgres fact' do
|
126
129
|
let(:target) { catalog.postgres.visits_fact }
|
127
130
|
|
128
|
-
subject(:result) { transform.define_table(target).to_s }
|
129
|
-
|
130
131
|
it 'should eq render table template' do
|
131
132
|
is_expected.to eq <<-EOS.strip_heredoc
|
132
133
|
CREATE TABLE IF NOT EXISTS visits_fact
|
@@ -149,7 +150,7 @@ describe Masamune::Transform::DefineTable do
|
|
149
150
|
context 'for postgres fact partition with :post' do
|
150
151
|
let(:target) { catalog.postgres.visits_fact.partition_table(Date.civil(2015, 01, 01)) }
|
151
152
|
|
152
|
-
|
153
|
+
let(:options) { {section: :post} }
|
153
154
|
|
154
155
|
it 'should eq render table template' do
|
155
156
|
is_expected.to match /ALTER TABLE visits_fact_y2015m01 INHERIT visits_fact;/
|
@@ -159,10 +160,10 @@ describe Masamune::Transform::DefineTable do
|
|
159
160
|
|
160
161
|
describe 'for fact table from file with sources files' do
|
161
162
|
let(:files) { (1..3).map { |i| double(path: "output_#{i}.csv") } }
|
162
|
-
let(:
|
163
|
+
let(:intermediate) { catalog.postgres.visits_fact }
|
163
164
|
let(:source) { catalog.postgres.visits_file }
|
164
|
-
|
165
|
-
|
165
|
+
let(:target) { source.stage_table(suffix: 'file', table: intermediate, inherit: false) }
|
166
|
+
let(:options) { { files: files} }
|
166
167
|
|
167
168
|
it 'should eq render table template' do
|
168
169
|
is_expected.to eq <<-EOS.strip_heredoc
|
@@ -200,15 +201,19 @@ describe Masamune::Transform::DefineTable do
|
|
200
201
|
EOS
|
201
202
|
end
|
202
203
|
|
203
|
-
context 'with file' do
|
204
|
-
|
204
|
+
context 'with single file' do
|
205
|
+
let(:target) { source.stage_table(table: intermediate) }
|
206
|
+
let(:options) { { files: files.first } }
|
207
|
+
|
205
208
|
it 'should eq render table template' do
|
206
209
|
is_expected.to_not be_nil
|
207
210
|
end
|
208
211
|
end
|
209
212
|
|
210
213
|
context 'with Set' do
|
211
|
-
|
214
|
+
let(:target) { source.stage_table(table: intermediate) }
|
215
|
+
let(:options) { { files: Set.new(files) } }
|
216
|
+
|
212
217
|
it 'should eq render table template' do
|
213
218
|
is_expected.to_not be_nil
|
214
219
|
end
|
@@ -228,8 +233,6 @@ describe Masamune::Transform::DefineTable do
|
|
228
233
|
|
229
234
|
let(:target) { catalog.postgres.visits_fact }
|
230
235
|
|
231
|
-
subject(:result) { transform.define_table(target).to_s }
|
232
|
-
|
233
236
|
it 'should eq render table template' do
|
234
237
|
is_expected.to eq <<-EOS.strip_heredoc
|
235
238
|
CREATE TABLE IF NOT EXISTS visits_fact
|
@@ -246,8 +249,6 @@ describe Masamune::Transform::DefineTable do
|
|
246
249
|
context 'for hive fact' do
|
247
250
|
let(:target) { catalog.hive.visits_hourly_fact }
|
248
251
|
|
249
|
-
subject(:result) { transform.define_table(target).to_s }
|
250
|
-
|
251
252
|
it 'should eq render table template' do
|
252
253
|
is_expected.to eq <<-EOS.strip_heredoc
|
253
254
|
CREATE TABLE IF NOT EXISTS visits_hourly_fact
|
@@ -23,8 +23,9 @@
|
|
23
23
|
describe Masamune::Transform::DefineTable do
|
24
24
|
let(:files) { [] }
|
25
25
|
let(:section) { :all }
|
26
|
+
let(:options) { { files: files, section: section } }
|
26
27
|
|
27
|
-
subject { transform.define_table(target,
|
28
|
+
subject { transform.define_table(target, options).to_s }
|
28
29
|
|
29
30
|
context 'for postgres table with columns' do
|
30
31
|
before do
|
@@ -875,6 +876,39 @@ describe Masamune::Transform::DefineTable do
|
|
875
876
|
end
|
876
877
|
end
|
877
878
|
|
879
|
+
context 'for postgres table with row data and section :pre' do
|
880
|
+
before do
|
881
|
+
catalog.schema :postgres do
|
882
|
+
table 'user_account_state' do
|
883
|
+
column 'name', type: :string, unique: true
|
884
|
+
column 'description', type: :string
|
885
|
+
row name: 'registered', description: 'Registered'
|
886
|
+
row name: 'active', description: 'Active', attributes: {default: true}
|
887
|
+
row name: 'inactive', description: 'Inactive'
|
888
|
+
end
|
889
|
+
end
|
890
|
+
end
|
891
|
+
|
892
|
+
let(:section) { :pre }
|
893
|
+
let(:target) { catalog.postgres.user_account_state_table }
|
894
|
+
|
895
|
+
it 'should render table template' do
|
896
|
+
is_expected.to eq <<-EOS.strip_heredoc
|
897
|
+
CREATE TABLE IF NOT EXISTS user_account_state_table
|
898
|
+
(
|
899
|
+
id SERIAL,
|
900
|
+
name VARCHAR NOT NULL,
|
901
|
+
description VARCHAR NOT NULL
|
902
|
+
);
|
903
|
+
|
904
|
+
CREATE OR REPLACE FUNCTION default_user_account_state_table_id()
|
905
|
+
RETURNS INTEGER IMMUTABLE AS $$
|
906
|
+
SELECT id FROM user_account_state_table WHERE name = 'active' AND description = 'Active';
|
907
|
+
$$ LANGUAGE SQL;
|
908
|
+
EOS
|
909
|
+
end
|
910
|
+
end
|
911
|
+
|
878
912
|
context 'for postgres table with unique columns and section :post' do
|
879
913
|
before do
|
880
914
|
catalog.schema :postgres do
|
@@ -54,18 +54,18 @@ describe Masamune::Transform::LoadDimension do
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
let(:
|
57
|
+
let(:files) { double(path: 'output.csv') }
|
58
58
|
let(:target) { catalog.postgres.user_dimension }
|
59
59
|
let(:source) { catalog.postgres.user_file }
|
60
60
|
let(:target_ledger) { target.ledger_table }
|
61
61
|
let(:source_table) { source.stage_table(suffix: 'file', table: target_ledger, inherit: false) }
|
62
62
|
|
63
63
|
context 'with postgres dimension' do
|
64
|
-
subject(:result) { transform.load_dimension(
|
64
|
+
subject(:result) { transform.load_dimension(files, source, target).to_s }
|
65
65
|
|
66
66
|
it 'should render combined template' do
|
67
67
|
is_expected.to eq Masamune::Template.combine \
|
68
|
-
transform.define_table(source_table,
|
68
|
+
transform.define_table(source_table, files: files),
|
69
69
|
transform.insert_reference_values(source_table, target_ledger),
|
70
70
|
transform.stage_dimension(source_table, target_ledger),
|
71
71
|
transform.bulk_upsert(target_ledger.stage_table, target_ledger)
|
@@ -79,7 +79,7 @@ describe Masamune::Transform::LoadFact do
|
|
79
79
|
|
80
80
|
it 'should render combined template' do
|
81
81
|
is_expected.to eq Masamune::Template.combine \
|
82
|
-
transform.define_table(source_table, files),
|
82
|
+
transform.define_table(source_table, files: files),
|
83
83
|
transform.insert_reference_values(source_table, target),
|
84
84
|
transform.stage_fact(source_table, target, date)
|
85
85
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: masamune
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.17.
|
4
|
+
version: 0.17.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Andrews
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|