masamune 0.17.4 → 0.17.5
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/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
|