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 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