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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 61f6f61c4cd5df082a7f5a63cee2f4f7716ff7ca
4
- data.tar.gz: 9a47bb9bbdb0339904cf8159968fe9fc0a6dc6aa
3
+ metadata.gz: 3067d46a85020fb673687d897550d3590dd34e15
4
+ data.tar.gz: 8f3a034427ba96b5209434cb997d1eb7c313e91d
5
5
  SHA512:
6
- metadata.gz: e7bd7a01c74b0779318dc2988c1741fed4122c866b913fe63457d4696a47794ffb540de0d363bb8d92b9f4836de3be1ed929dc741a90085c093b216728e8aaae
7
- data.tar.gz: 5ec032b8c286a99d8873a03525ba6c02c2f090567e7a451711423b6e2fd2f6d87133deabafcd527dd149b502b1c5c07ff03bff6b24037bd202a44143ded3cd1d
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, [], options[:section])
38
+ operators << define_table(dimension, options)
39
39
  end
40
40
 
41
41
  context.facts.each do |_, fact|
42
- operators << define_table(fact, [], options[:section])
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, [], options[:section])
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, files = [], section = nil)
27
+ def define_table(target, options = {})
28
28
  return if target.implicit
29
- Operator.new(__method__, target: target, files: files, section: section).tap do |operator|
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
@@ -21,5 +21,5 @@
21
21
  # THE SOFTWARE.
22
22
 
23
23
  module Masamune
24
- VERSION = '0.17.4'
24
+ VERSION = '0.17.5'
25
25
  end
@@ -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 'without start_date and stop_date' do
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
- subject { transform.define_table(table).to_s }
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
- subject(:result) { transform.define_table(target, [], :post).to_s }
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(:target) { catalog.postgres.visits_fact }
163
+ let(:intermediate) { catalog.postgres.visits_fact }
163
164
  let(:source) { catalog.postgres.visits_file }
164
-
165
- subject(:result) { transform.define_table(source.stage_table(suffix: 'file', table: target, inherit: false), files).to_s }
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
- subject(:result) { transform.define_table(source.stage_table(table: target), files.first).to_s }
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
- subject(:result) { transform.define_table(source.stage_table(table: target), Set.new(files)).to_s }
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, files, section).to_s }
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(:data) { double(path: 'output.csv') }
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(data, source, target).to_s }
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, data),
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
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-08 00:00:00.000000000 Z
11
+ date: 2016-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor