masamune 0.13.0 → 0.13.1

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: 77bd1d9e8351f259a7d946ac7b2abd11b4c14408
4
- data.tar.gz: deb47f8efaadd8b90b5825f79970e46833bbb030
3
+ metadata.gz: 49fdc180c59d4179763efd965d946c93fb864dcf
4
+ data.tar.gz: 0765d61a7a7247c7bb5eb0d70d17c7edb5e5fcf5
5
5
  SHA512:
6
- metadata.gz: 784416ce6169e2c3f2a9a14465580417ecfc6bdd73e238643022f608a9a04ede66d0b670dfce06e0956b14d3d96a8edbcbe0018ee76bdd0e1ccd4c2bb9f4b37a
7
- data.tar.gz: 6b1cb22550d392cb6bf6cf36258d21b28e7c323dd6bab5616b4066380e315bcb289c725d52a36f65cd182293c1a28d68f31e928a642d5429ce1f024945f2d81a
6
+ metadata.gz: 7a121d38a8d42a7e0c255ba17e523e1520da7016e0a87d553adcd32c67f6af21eb2ffc81cbcda1123e286fd93cdde8b31177affa30e17314497248d820fea989
7
+ data.tar.gz: 93ab83f1f5804d0b3bf25970a665d63f3e7099c43ec6c817e8a04ee30ad3dde348aa4a2515a1a8518e76aeb0150eed04a77cf1a568710f806dbe4582f1502259
@@ -30,7 +30,7 @@ module Masamune::Actions
30
30
  def parse_datetime_type(key)
31
31
  value = options[key]
32
32
  Chronic.parse(value).tap do |datetime_value|
33
- console("Using '#{datetime_value}' for --#{key}") if value != datetime_value
33
+ logger.debug("Using '#{datetime_value}' for --#{key}") if value != datetime_value
34
34
  end or raise Thor::MalformattedArgumentError, "Expected date time value for '--#{key}'; got #{value}"
35
35
  end
36
36
 
@@ -30,12 +30,14 @@ module Masamune::Commands
30
30
  {
31
31
  :create_db_path => 'createdb',
32
32
  :drop_db_path => 'dropdb',
33
+ :pg_dump_path => 'pg_dump',
33
34
  :options => [],
34
35
  :hostname => 'localhost',
35
36
  :username => 'postgres',
36
37
  :pgpass_file => nil,
37
38
  :action => nil,
38
- :database => nil
39
+ :database => nil,
40
+ :output => nil
39
41
  }
40
42
 
41
43
  def initialize(delegate, attrs = {})
@@ -52,7 +54,9 @@ module Masamune::Commands
52
54
  args << '--host=%s' % @hostname if @hostname
53
55
  args << '--username=%s' % @username if @username
54
56
  args << '--no-password'
55
- args << @database
57
+ args << database
58
+ args << @options
59
+ args << output
56
60
  args.flatten.compact
57
61
  end
58
62
 
@@ -64,9 +68,21 @@ module Masamune::Commands
64
68
  [@create_db_path]
65
69
  when :drop
66
70
  [@drop_db_path, '--if-exists']
71
+ when :dump
72
+ [@pg_dump_path, '--no-owner', '--no-privileges', '--oids', '--schema=public']
67
73
  else
68
- raise ArgumentError, ':action must be :create or :drop'
74
+ raise ArgumentError, ':action must be :create, :drop, or :dump'
69
75
  end
70
76
  end
77
+
78
+ def database
79
+ return @database unless @action == :dump
80
+ '--dbname=%s' % @database
81
+ end
82
+
83
+ def output
84
+ return unless @action == :dump
85
+ '--file=%s' % @output if @output
86
+ end
71
87
  end
72
88
  end
@@ -109,9 +109,18 @@ class Masamune::DataPlan::Rule
109
109
  matched_pattern.present? && matched_pattern[:rest].blank?
110
110
  end
111
111
 
112
- def bind_date(input_date)
113
- output_date = tz.utc_to_local(input_date)
114
- Masamune::DataPlan::Elem.new(self, output_date, options_for_elem)
112
+ def bind_date_or_time(input = nil)
113
+ input_time =
114
+ case input
115
+ when Time, DateTime
116
+ input
117
+ when Date
118
+ input.to_time
119
+ else
120
+ raise ArgumentError, "Cannot bind_date_or_time with type #{input.class}"
121
+ end
122
+ output_time = tz.utc_to_local(input_time)
123
+ Masamune::DataPlan::Elem.new(self, output_time, options_for_elem)
115
124
  end
116
125
 
117
126
  def bind_input(input)
@@ -123,12 +132,12 @@ class Masamune::DataPlan::Rule
123
132
  end
124
133
 
125
134
  def unify(elem, rule)
126
- rule.bind_date(elem.start_time)
135
+ rule.bind_date_or_time(elem.start_time)
127
136
  end
128
137
 
129
138
  def generate(start_time, stop_time)
130
139
  return Set.new(to_enum(:generate, start_time, stop_time)) unless block_given?
131
- instance = bind_date(start_time)
140
+ instance = bind_date_or_time(start_time)
132
141
 
133
142
  begin
134
143
  yield instance
@@ -85,17 +85,28 @@ module Masamune::Schema
85
85
  end
86
86
  end
87
87
 
88
- def partition_table(date)
89
- partition_range = partition_rule.bind_date(date)
88
+ def partition_table(date = nil)
89
+ return unless partition
90
+ return unless date
91
+ partition_range = partition_rule.bind_date_or_time(date)
90
92
  @partition_tables ||= {}
91
93
  @partition_tables[partition_range] ||= self.class.new(id: @id, store: store, columns: partition_table_columns, parent: self, range: partition_range, grain: grain, inherit: true)
92
94
  end
93
95
 
96
+ def partition_tables(start_date = nil, stop_date = nil)
97
+ return unless partition
98
+ return unless start_date && stop_date
99
+ (start_date .. stop_date).each do |date|
100
+ next unless date.day == 1
101
+ yield partition_table(date)
102
+ end
103
+ end
104
+
94
105
  def measures
95
106
  columns.select { |_, column| column.measure }
96
107
  end
97
108
 
98
- def constraints
109
+ def inheritance_constraints
99
110
  return unless range
100
111
  "CHECK (time_key >= #{range.start_time.to_i} AND time_key < #{range.stop_time.to_i})"
101
112
  end
@@ -183,8 +183,13 @@ module Masamune::Schema
183
183
  return to_enum(__method__).to_a.flatten.compact unless block_given?
184
184
  columns.map do |_, column|
185
185
  next if column.surrogate_key || column.ignore
186
- if column.reference
187
- (column.reference.natural_keys.any? ? column.reference.natural_keys : column.reference.denormalized_columns).each do |join_column|
186
+ if column.reference && column.reference.natural_keys.any?
187
+ column.reference.natural_keys.each do |join_column|
188
+ next if join_column.reference && join_column.natural_key
189
+ yield [column.reference, join_column]
190
+ end
191
+ elsif column.reference && column.reference.denormalized_columns.any?
192
+ column.reference.denormalized_columns.each do |join_column|
188
193
  yield [column.reference, join_column]
189
194
  end
190
195
  else
@@ -26,6 +26,7 @@ require 'thor'
26
26
  module Masamune::Tasks
27
27
  class DumpThor < Thor
28
28
  include Masamune::Thor
29
+ include Masamune::Actions::DateParse
29
30
  include Masamune::Transform::DefineSchema
30
31
 
31
32
  # FIXME need to add an unnecessary namespace until this issue is fixed:
@@ -35,9 +36,7 @@ module Masamune::Tasks
35
36
 
36
37
  desc 'dump', 'Dump schema'
37
38
  method_option :type, :enum => ['psql', 'hql'], :desc => 'Schema type', :default => 'psql'
38
- method_option :with_index, :type => :boolean, :desc => 'Dump schema with indexes', :default => true
39
- method_option :with_foreign_key, :type => :boolean, :desc => 'Dump schema with foreign key constraints', :default => true
40
- method_option :with_unique_constraint, :type => :boolean, :desc => 'Dump schema with uniqueness constraints', :default => true
39
+ method_option :section, :enum => ['pre', 'post', 'all'], :desc => 'Schema section', :default => 'all'
41
40
  def dump_exec
42
41
  print_catalog
43
42
  exit
@@ -49,10 +48,18 @@ module Masamune::Tasks
49
48
  def print_catalog
50
49
  case options[:type]
51
50
  when 'psql'
52
- puts define_schema(catalog, :postgres, options.slice(:with_index, :with_foreign_key, :with_unique_constraint).to_h.symbolize_keys)
51
+ puts define_schema(catalog, :postgres, define_schema_options)
53
52
  when 'hql'
54
- puts define_schema(catalog, :hive)
53
+ puts define_schema(catalog, :hive, define_schema_options)
55
54
  end
56
55
  end
56
+
57
+ def define_schema_options
58
+ {
59
+ section: options[:section].to_sym,
60
+ start_date: start_date,
61
+ stop_date: stop_date
62
+ }.reject { |_, v| v.blank? }
63
+ end
57
64
  end
58
65
  end
@@ -56,7 +56,7 @@ module Masamune
56
56
  end
57
57
 
58
58
  def render_to_string(template, parameters = {})
59
- instance = Template.new(File.dirname(template))
59
+ instance = self.new(File.dirname(template))
60
60
  combine instance.render(template, parameters)
61
61
  end
62
62
 
@@ -0,0 +1,28 @@
1
+ -- The MIT License (MIT)
2
+ --
3
+ -- Copyright (c) 2014-2015, VMware, Inc. All Rights Reserved.
4
+ --
5
+ -- Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ -- of this software and associated documentation files (the "Software"), to deal
7
+ -- in the Software without restriction, including without limitation the rights
8
+ -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ -- copies of the Software, and to permit persons to whom the Software is
10
+ -- furnished to do so, subject to the following conditions:
11
+ --
12
+ -- The above copyright notice and this permission notice shall be included in
13
+ -- all copies or substantial portions of the Software.
14
+ --
15
+ -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ -- THE SOFTWARE.
22
+
23
+ <%- if target.parent -%>
24
+ ALTER TABLE <%= target.name %> INHERIT <%= target.parent.name %>;
25
+ <%- end -%>
26
+ <%- if target.inheritance_constraints -%>
27
+ ALTER TABLE <%= target.name %> ADD CONSTRAINT <%= target.name %>_time_key_check <%= target.inheritance_constraints %>;
28
+ <%- end -%>
@@ -35,11 +35,14 @@ module Masamune::Transform
35
35
  operators += context.extra(:pre)
36
36
 
37
37
  context.dimensions.each do |_, dimension|
38
- operators << define_table(dimension, [], options)
38
+ operators << define_table(dimension, [], options[:section])
39
39
  end
40
40
 
41
41
  context.facts.each do |_, fact|
42
- operators << define_table(fact, [], options)
42
+ operators << define_table(fact, [], options[:section])
43
+ fact.partition_tables(options[:start_date], options[:stop_date]) do |fact_partition_table|
44
+ operators << define_table(fact_partition_table, [], options[:section])
45
+ end
43
46
  end
44
47
 
45
48
  operators += context.extra(:post)
@@ -22,22 +22,22 @@
22
22
 
23
23
  <%
24
24
  files ||= []
25
- with_index = locals.fetch(:with_index, true)
26
- with_foreign_key = locals.fetch(:with_foreign_key, true)
27
- with_unique_constraint = locals.fetch(:with_unique_constraint, true)
28
25
  %>
29
26
 
30
27
  <%- target.children.each do |child| -%>
31
28
  <%= render 'define_table.psql.erb', target: child, **locals.except(:target, :files) %>
32
29
  <%- end -%>
33
30
 
31
+ <%- if helper.define_types? %>
34
32
  <%- target.enum_columns.each do |_, column| -%>
35
33
  DO $$ BEGIN
36
34
  IF NOT EXISTS (SELECT 1 FROM pg_type t WHERE LOWER(t.typname) = LOWER('<%= column.sql_type %>')) THEN
37
35
  CREATE TYPE <%= column.sql_type %> AS ENUM (<%= column.values.map { |value| "'#{value}'" }.join(', ') %>);
38
36
  END IF; END $$;
39
37
  <%- end -%>
38
+ <%- end -%>
40
39
 
40
+ <%- if helper.define_sequences? %>
41
41
  <%- target.sequence_columns.each do |_, column| -%>
42
42
  DO $$ BEGIN
43
43
  IF NOT EXISTS (SELECT 1 FROM pg_class c WHERE c.relname = '<%= column.sequence_id %>') THEN
@@ -45,7 +45,9 @@ CREATE SEQUENCE <%= column.sequence_id %>;
45
45
  ALTER SEQUENCE <%= column.sequence_id %> RESTART <%= column.sequence_offset %>;
46
46
  END IF; END $$;
47
47
  <%- end -%>
48
+ <%- end -%>
48
49
 
50
+ <%- if helper.define_tables? %>
49
51
  <%- if target.temporary? -%>
50
52
  CREATE TEMPORARY TABLE IF NOT EXISTS <%= target.name %>
51
53
  <%- else -%>
@@ -56,25 +58,29 @@ CREATE TABLE IF NOT EXISTS <%= target.name %>
56
58
  <%= column.as_psql %><%= ',' unless last %>
57
59
  <%- end -%>
58
60
  );
61
+ <%- end -%>
59
62
 
60
- <%- unless target.temporary? || target.primary_keys.empty? -%>
63
+ <%- if helper.define_primary_keys? %>
61
64
  DO $$ BEGIN
62
65
  IF NOT EXISTS (SELECT 1 FROM pg_class c WHERE c.relname = '<%= target.name %>_pkey') THEN
63
66
  ALTER TABLE <%= target.name %> ADD PRIMARY KEY (<%= target.primary_keys.map(&:name).join(', ') %>);
64
67
  END IF; END $$;
65
68
  <%- end -%>
66
69
 
67
- <%- if with_foreign_key && !target.delay_constraints? -%>
70
+ <%- if helper.define_foreign_keys? -%>
68
71
  <%= render 'define_foreign_key.psql.erb', target: target %>
69
72
  <%- end -%>
70
73
 
74
+ <%- if helper.define_sequences? -%>
71
75
  <%- target.sequence_columns.each do |_, column| -%>
72
76
  DO $$ BEGIN
73
77
  IF NOT EXISTS (SELECT 1 WHERE sequence_owner('<%= column.sequence_id %>') = '<%= column.qualified_name %>') THEN
74
78
  ALTER SEQUENCE <%= column.sequence_id %> OWNED BY <%= column.qualified_name %>;
75
79
  END IF; END $$;
76
80
  <%- end -%>
81
+ <%- end -%>
77
82
 
83
+ <%- if helper.load_files? -%>
78
84
  <%- files.each do |file| -%>
79
85
  <%-
80
86
  copy_options = []
@@ -84,25 +90,33 @@ END IF; END $$;
84
90
  -%>
85
91
  COPY <%= target.name %> FROM '<%= file %>' WITH (<%= copy_options.join(", ") %>);
86
92
  <%- end -%>
93
+ <%- end -%>
87
94
 
88
- <%- if with_unique_constraint && !target.delay_constraints? -%>
95
+ <%- if helper.define_inheritance? -%>
96
+ <%= render 'define_inheritance.psql.erb', target: target %>
97
+ <%- end -%>
98
+
99
+ <%- if helper.define_unique_constraints? -%>
89
100
  <%= render 'define_unique.psql.erb', target: target %>
90
101
  <%- end -%>
91
102
 
92
- <%- if with_index && !target.delay_index? -%>
103
+ <%- if helper.define_indexes? -%>
93
104
  <%= render 'define_index.psql.erb', target: target %>
94
105
  <%- end -%>
95
106
 
107
+ <%- if helper.insert_rows? -%>
96
108
  <% target.insert_rows.each do |row| %>
97
109
  INSERT INTO <%= target.name %> (<%= row.insert_columns.join(', ') %>)
98
110
  SELECT <%= row.insert_values.join(', ') %>
99
111
  WHERE NOT EXISTS (SELECT 1 FROM <%= target.name %> WHERE <%= row.insert_constraints.join(' AND ') %>);
100
112
  <%- end -%>
113
+ <%- end -%>
101
114
 
102
- <%- if files.any? || target.insert_rows.any? -%>
115
+ <%- if helper.perform_analyze? -%>
103
116
  ANALYZE <%= target.name %>;
104
117
  <%- end -%>
105
118
 
119
+ <%- if helper.define_functions? -%>
106
120
  <% target.aliased_rows.each do |row| %>
107
121
  <%- row.natural_keys.each do |column| -%>
108
122
  CREATE OR REPLACE FUNCTION <%= row.name(column) %>
@@ -118,3 +132,4 @@ RETURNS <%= target.surrogate_key.sql_type %> IMMUTABLE AS $$
118
132
  $$ LANGUAGE SQL;
119
133
 
120
134
  <%- end -%>
135
+ <%- end -%>
@@ -24,23 +24,114 @@ module Masamune::Transform
24
24
  module DefineTable
25
25
  extend ActiveSupport::Concern
26
26
 
27
- def define_table(target, files = [], options = {})
27
+ def define_table(target, files = [], section = nil)
28
28
  return if target.implicit
29
- Operator.new(__method__, target: target, files: Masamune::Schema::Map.convert_files(files), **options.slice(:with_index, :with_foreign_key, :with_unique_constraint), presenters: { postgres: Postgres, hive: Hive }).tap do |operator|
29
+ Operator.new(__method__, target: target, files: Masamune::Schema::Map.convert_files(files), section: section, helper: Helper, presenters: { postgres: Postgres, hive: Hive }).tap do |operator|
30
30
  logger.debug("#{target.id}\n" + operator.to_s) if target.debug
31
31
  end
32
32
  end
33
33
 
34
+ class Helper < SimpleDelegator
35
+ def files
36
+ locals[:files]
37
+ end
38
+
39
+ def section
40
+ locals[:section] || :all
41
+ end
42
+
43
+ def define_types?
44
+ !post_section?
45
+ end
46
+
47
+ def define_tables?
48
+ !post_section?
49
+ end
50
+
51
+ def define_functions?
52
+ !post_section?
53
+ end
54
+
55
+ def define_sequences?
56
+ !post_section?
57
+ end
58
+
59
+ def define_primary_keys?
60
+ !pre_section? && !(target.temporary? || target.primary_keys.empty?)
61
+ end
62
+
63
+ def define_inheritance?
64
+ return false unless target.inherited?
65
+ return false if pre_section?
66
+ return true if post_section?
67
+ !target.delay_indexes?
68
+ end
69
+
70
+ def define_indexes?
71
+ return false if pre_section?
72
+ return true if post_section?
73
+ !target.delay_indexes?
74
+ end
75
+
76
+ def define_foreign_keys?
77
+ return false if pre_section?
78
+ return true if post_section?
79
+ !target.delay_foreign_keys?
80
+ end
81
+
82
+ def define_unique_constraints?
83
+ return false if pre_section?
84
+ return true if post_section?
85
+ !target.delay_unique_constraints?
86
+ end
87
+
88
+ def insert_rows?
89
+ !post_section?
90
+ end
91
+
92
+ def load_files?
93
+ all_section?
94
+ end
95
+
96
+ def perform_analyze?
97
+ return false if pre_section?
98
+ return true if post_section?
99
+ files.any? || target.insert_rows.any?
100
+ end
101
+
102
+ private
103
+
104
+ def all_section?
105
+ section == :all
106
+ end
107
+
108
+ def pre_section?
109
+ section == :pre
110
+ end
111
+
112
+ def post_section?
113
+ section == :post
114
+ end
115
+ end
116
+
34
117
  class Postgres < SimpleDelegator
35
118
  def children
36
119
  super.map { |child| self.class.new(child) }
37
120
  end
38
121
 
39
- def delay_index?
122
+ def inherited?
123
+ type == :fact && inheritance_constraints
124
+ end
125
+
126
+ def delay_indexes?
127
+ type == :fact
128
+ end
129
+
130
+ def delay_foreign_keys?
40
131
  type == :fact
41
132
  end
42
133
 
43
- def delay_constraints?
134
+ def delay_unique_constraints?
44
135
  type == :fact
45
136
  end
46
137
  end