masamune 0.11.5 → 0.11.6

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: 575463d3df3f7dd11eb973b5611b67d2c8feeeda
4
- data.tar.gz: fc08c068a9161aa2cafcbad96266e589bf77b3af
3
+ metadata.gz: 16d125ee3baa02af550e3e1be25c02f2e01f3ffa
4
+ data.tar.gz: 0ed7d28ecc6daaf83699138ac0b4b1acdb8363f9
5
5
  SHA512:
6
- metadata.gz: 14298e5d7168af6f03d8b26acc31ec8a3302a990e8ac68faab544db2f028bb61b5579f48916e7d833665c7976a73b1ec36d1318be3e11059f11d7d9c694a9a42
7
- data.tar.gz: 5debba170513313ab984f1d9a5de7516563c83511191a863512ab11ca3b76d0e599b0cd93ed9b72c7d3237ecc731ffdaa156a986933477d1be496d5d97a0a646
6
+ metadata.gz: 07aa680b40ea443bc1d6609b03c57a988a7d519739db1ce7cbefef54e09f408920b7424e73815f4fb4c0b588a2adec984b35432c220cfdc08bb19bfb0a161879
7
+ data.tar.gz: 01794b4dca6b07019aa83976ca6e72620e4c8dd3cbb1ff13b59fbc9d941bf7d2cd7ad59c5d2ac009585702d30554d3990b927bbb2b8fc9bda4a9b4569f6d24de
@@ -57,6 +57,21 @@ module Masamune::Actions
57
57
  Set.new File.read(value).split(/\s+/)
58
58
  end
59
59
 
60
+ def execute(options = {})
61
+ raise Thor::RequiredArgumentMissingError, "No value provided for required options '--start' or '--at'" unless options[:start] || options[:at] || options[:sources] || options[:targets]
62
+ raise Thor::MalformattedArgumentError, "Cannot specify both option '--sources' and option '--targets'" if options[:sources] && options[:targets]
63
+
64
+ desired_sources = Masamune::DataPlan::Set.new current_command_name, parse_file_type(:sources)
65
+ desired_targets = Masamune::DataPlan::Set.new current_command_name, parse_file_type(:targets)
66
+
67
+ if start_time && stop_time
68
+ desired_targets.merge engine.targets_for_date_range(current_command_name, start_time, stop_time)
69
+ end
70
+
71
+ engine.prepare(current_command_name, options.merge(sources: desired_sources, targets: desired_targets))
72
+ engine.execute(current_command_name, options)
73
+ end
74
+
60
75
  private
61
76
 
62
77
  included do |base|
@@ -68,23 +83,11 @@ module Masamune::Actions
68
83
  end
69
84
 
70
85
  base.after_initialize(:final) do |thor, options|
71
- # Only execute this block if DataPlan::Engine is not currently executing
72
- next if thor.engine.executing?
73
86
  thor.engine.environment = thor.environment
74
87
  thor.engine.filesystem.environment = thor.environment
75
-
76
- raise Thor::RequiredArgumentMissingError, "No value provided for required options '--start' or '--at'" unless options[:start] || options[:at] || options[:sources] || options[:targets]
77
- raise Thor::MalformattedArgumentError, "Cannot specify both option '--sources' and option '--targets'" if options[:sources] && options[:targets]
78
-
79
- desired_sources = Masamune::DataPlan::Set.new thor.current_command_name, thor.parse_file_type(:sources)
80
- desired_targets = Masamune::DataPlan::Set.new thor.current_command_name, thor.parse_file_type(:targets)
81
-
82
- if thor.start_time && thor.stop_time
83
- desired_targets.merge thor.engine.targets_for_date_range(thor.current_command_name, thor.start_time, thor.stop_time)
88
+ thor.environment.with_process_lock(:data_flow_after_initialize) do
89
+ thor.execute(options)
84
90
  end
85
-
86
- thor.engine.prepare(thor.current_command_name, options.merge(sources: desired_sources, targets: desired_targets))
87
- thor.engine.execute(thor.current_command_name, options)
88
91
  exit 0 if thor.top_level?
89
92
  end if defined?(base.after_initialize)
90
93
  end
@@ -58,9 +58,7 @@ class Masamune::DataPlan::Builder
58
58
 
59
59
  def thor_command_wrapper
60
60
  Proc.new do |engine, rule, _|
61
- engine.environment.with_exclusive_lock(rule) do
62
- engine.environment.parent.invoke(rule)
63
- end
61
+ engine.environment.parent.invoke(rule)
64
62
  end
65
63
  end
66
64
  end
@@ -141,10 +141,6 @@ class Masamune::DataPlan::Engine
141
141
  clear!
142
142
  end
143
143
 
144
- def executing?
145
- @current_depth > 0
146
- end
147
-
148
144
  def constrain_max_depth(rule)
149
145
  @current_depth += 1
150
146
  raise "Max depth of #{MAX_DEPTH} exceeded for rule '#{rule}'" if @current_depth > MAX_DEPTH
@@ -53,16 +53,18 @@ module Masamune
53
53
  @mutex ||= Mutex.new
54
54
  end
55
55
 
56
- def with_exclusive_lock(name, &block)
56
+ def with_exclusive_lock(name, options = {}, &block)
57
57
  raise 'filesystem path :run_dir not defined' unless filesystem.has_path?(:run_dir)
58
58
  lock_name = [name, configuration.lock].compact.join(':')
59
59
  logger.debug("acquiring lock '#{lock_name}'")
60
60
  lock_file = lock_file(lock_name)
61
- lock_status = lock_file.flock(File::LOCK_EX | File::LOCK_NB)
61
+ lock_mode = File::LOCK_EX
62
+ lock_mode |= File::LOCK_NB if options[:non_blocking]
63
+ lock_status = lock_file.flock(lock_mode)
62
64
  if lock_status == 0
63
65
  yield if block_given?
64
66
  else
65
- logger.error "acquire lock attempt failed for '#{lock_name}'"
67
+ logger.error "acquire lock attempt failed for '#{lock_name}'" unless options[:non_blocking]
66
68
  end
67
69
  ensure
68
70
  if lock_file
@@ -71,6 +73,12 @@ module Masamune
71
73
  end
72
74
  end
73
75
 
76
+ def with_process_lock(name)
77
+ with_exclusive_lock("#{name}_#{Process.pid}", non_blocking: true) do
78
+ yield
79
+ end
80
+ end
81
+
74
82
  def log_file_template
75
83
  @log_file_template || "#{Time.now.to_i}-#{$$}.log"
76
84
  end
@@ -39,7 +39,7 @@ module Masamune::Helpers
39
39
  end
40
40
 
41
41
  def database_exists?
42
- postgres(exec: 'SELECT version();', fail_fast: false).success?
42
+ @database_exists ||= postgres(exec: 'SELECT version();', fail_fast: false).success?
43
43
  end
44
44
 
45
45
  def table_exists?(table)
data/lib/masamune/thor.rb CHANGED
@@ -160,6 +160,18 @@ module Masamune
160
160
  def top_level?
161
161
  self.current_command_name == ARGV.first
162
162
  end
163
+
164
+ def invoke_command(command, *args)
165
+ environment.with_exclusive_lock(command.name, non_blocking: true) do
166
+ super
167
+ end
168
+ end
169
+
170
+ def invoke(name = nil, *args)
171
+ environment.with_exclusive_lock(name, non_blocking: top_level?) do
172
+ super
173
+ end
174
+ end
163
175
  end
164
176
 
165
177
  private
@@ -27,6 +27,7 @@ module Masamune
27
27
  require 'masamune/transform/define_table'
28
28
  require 'masamune/transform/define_event_view'
29
29
  require 'masamune/transform/define_schema'
30
+ require 'masamune/transform/denormalize_table'
30
31
 
31
32
  require 'masamune/transform/bulk_upsert'
32
33
  require 'masamune/transform/insert_reference_values'
@@ -0,0 +1,39 @@
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
+ SELECT
24
+ <%- target.select_columns(columns).each do |column, last| -%>
25
+ <%= column %><%= ',' unless last %>
26
+ <%- end -%>
27
+ FROM
28
+ <%= target.name %>
29
+ <%- target.join_conditions(columns).each do |table, condition| -%>
30
+ JOIN
31
+ <%= table %>
32
+ ON
33
+ <%= condition %>
34
+ <%- end -%>
35
+ ORDER BY
36
+ <%- target.order_by_columns(columns).each do |column, last| -%>
37
+ <%= column %><%= ',' unless last %>
38
+ <%- end -%>
39
+ ;
@@ -0,0 +1,71 @@
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
+ module Masamune::Transform
24
+ module DenormalizeTable
25
+ extend ActiveSupport::Concern
26
+
27
+ def denormalize_table(target, columns = [])
28
+ Operator.new(__method__, target: target, columns: columns, presenters: { postgres: Postgres })
29
+ end
30
+
31
+ private
32
+
33
+ class Postgres < SimpleDelegator
34
+ include Masamune::LastElement
35
+
36
+ def select_columns(column_names)
37
+ column_names.map do |column_name|
38
+ next unless column = dereference_column_name(column_name)
39
+ if column.reference
40
+ "#{column.foreign_key_name} AS #{column.name}"
41
+ else
42
+ column.qualified_name
43
+ end
44
+ end.compact
45
+ end
46
+ method_with_last_element :select_columns
47
+
48
+ def join_conditions(column_names)
49
+ {}.tap do |conditions|
50
+ column_names.each do |column_name|
51
+ next unless column = dereference_column_name(column_name)
52
+ next unless column.reference
53
+ adjacent_reference = references[column.reference.id]
54
+ next unless adjacent_reference
55
+ adjacent_column = columns[adjacent_reference.foreign_key_name]
56
+ next unless adjacent_column
57
+ conditions[column.reference.name] = "#{column.reference.surrogate_key.qualified_name} = #{adjacent_column.qualified_name}"
58
+ end
59
+ end
60
+ end
61
+
62
+ def order_by_columns(column_names)
63
+ column_names.map do |column_name|
64
+ next unless column = dereference_column_name(column_name)
65
+ column.name
66
+ end.compact
67
+ end
68
+ method_with_last_element :order_by_columns
69
+ end
70
+ end
71
+ end
@@ -21,5 +21,5 @@
21
21
  # THE SOFTWARE.
22
22
 
23
23
  module Masamune
24
- VERSION = '0.11.5'
24
+ VERSION = '0.11.6'
25
25
  end
@@ -0,0 +1,125 @@
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
+ require 'spec_helper'
24
+
25
+ describe Masamune::Transform::DenormalizeTable do
26
+ before do
27
+ catalog.schema :postgres do
28
+ dimension 'cluster', type: :mini do
29
+ column 'id', type: :sequence, surrogate_key: true, auto: true
30
+ column 'name', type: :string
31
+
32
+ row name: 'current_database()', attributes: {default: true}
33
+ end
34
+
35
+ dimension 'date', type: :date do
36
+ column 'date_id', type: :integer, unique: true, index: true, natural_key: true
37
+ end
38
+
39
+ dimension 'tenant', type: :two do
40
+ column 'tenant_id', type: :integer, index: true, natural_key: true
41
+ end
42
+
43
+ dimension 'user', type: :two do
44
+ column 'tenant_id', type: :integer, index: true, natural_key: true
45
+ column 'user_id', type: :integer, index: true, natural_key: true
46
+ end
47
+
48
+ dimension 'user_agent', type: :mini do
49
+ column 'name', type: :string, unique: true, index: 'shared'
50
+ column 'version', type: :string, unique: true, index: 'shared', default: 'Unknown'
51
+ column 'mobile', type: :boolean, unique: true, index: 'shared', default: false
52
+ column 'description', type: :string, null: true, ignore: true
53
+ end
54
+
55
+ fact 'visits', partition: 'y%Ym%m' do
56
+ references :cluster
57
+ references :date
58
+ references :tenant
59
+ references :user
60
+ references :user_agent
61
+ measure 'total', type: :integer
62
+ end
63
+ end
64
+ end
65
+
66
+ let(:target) { catalog.postgres.visits_fact }
67
+ let(:columns) do
68
+ [
69
+ 'date.date_id',
70
+ 'tenant.tenant_id',
71
+ 'user.tenant_id',
72
+ 'user.user_id',
73
+ 'user_agent.name',
74
+ 'user_agent.version',
75
+ 'total',
76
+ 'time_key'
77
+ ]
78
+ end
79
+
80
+ context 'with postgres fact' do
81
+ subject(:result) { transform.denormalize_table(target, columns).to_s }
82
+
83
+ it 'should eq render denormalize_table template' do
84
+ is_expected.to eq <<-EOS.strip_heredoc
85
+ SELECT
86
+ date_dimension.date_id AS date_dimension_date_id,
87
+ tenant_dimension.tenant_id AS tenant_dimension_tenant_id,
88
+ user_dimension.tenant_id AS user_dimension_tenant_id,
89
+ user_dimension.user_id AS user_dimension_user_id,
90
+ user_agent_type.name AS user_agent_type_name,
91
+ user_agent_type.version AS user_agent_type_version,
92
+ visits_fact.total,
93
+ visits_fact.time_key
94
+ FROM
95
+ visits_fact
96
+ JOIN
97
+ date_dimension
98
+ ON
99
+ date_dimension.id = visits_fact.date_dimension_id
100
+ JOIN
101
+ tenant_dimension
102
+ ON
103
+ tenant_dimension.id = visits_fact.tenant_dimension_id
104
+ JOIN
105
+ user_dimension
106
+ ON
107
+ user_dimension.id = visits_fact.user_dimension_id
108
+ JOIN
109
+ user_agent_type
110
+ ON
111
+ user_agent_type.id = visits_fact.user_agent_type_id
112
+ ORDER BY
113
+ date_dimension_date_id,
114
+ tenant_dimension_tenant_id,
115
+ user_dimension_tenant_id,
116
+ user_dimension_user_id,
117
+ user_agent_type_name,
118
+ user_agent_type_version,
119
+ total,
120
+ time_key
121
+ ;
122
+ EOS
123
+ end
124
+ end
125
+ 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.11.5
4
+ version: 0.11.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Andrews
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-15 00:00:00.000000000 Z
11
+ date: 2015-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -114,14 +114,28 @@ dependencies:
114
114
  requirements:
115
115
  - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: 0.10.1
117
+ version: '0'
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: 0.10.1
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rb-readline
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: rake
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -264,6 +278,8 @@ files:
264
278
  - lib/masamune/transform/define_table.psql.erb
265
279
  - lib/masamune/transform/define_table.rb
266
280
  - lib/masamune/transform/define_unique.psql.erb
281
+ - lib/masamune/transform/denormalize_table.psql.erb
282
+ - lib/masamune/transform/denormalize_table.rb
267
283
  - lib/masamune/transform/insert_reference_values.psql.erb
268
284
  - lib/masamune/transform/insert_reference_values.rb
269
285
  - lib/masamune/transform/load_dimension.rb
@@ -339,6 +355,7 @@ files:
339
355
  - spec/masamune/transform/define_table.dimension_spec.rb
340
356
  - spec/masamune/transform/define_table.fact_spec.rb
341
357
  - spec/masamune/transform/define_table.table_spec.rb
358
+ - spec/masamune/transform/denormalize_table_spec.rb
342
359
  - spec/masamune/transform/insert_reference_values.dimension_spec.rb
343
360
  - spec/masamune/transform/insert_reference_values.fact_spec.rb
344
361
  - spec/masamune/transform/load_dimension_spec.rb
@@ -442,6 +459,7 @@ test_files:
442
459
  - spec/masamune/transform/define_table.dimension_spec.rb
443
460
  - spec/masamune/transform/define_table.fact_spec.rb
444
461
  - spec/masamune/transform/define_table.table_spec.rb
462
+ - spec/masamune/transform/denormalize_table_spec.rb
445
463
  - spec/masamune/transform/insert_reference_values.dimension_spec.rb
446
464
  - spec/masamune/transform/insert_reference_values.fact_spec.rb
447
465
  - spec/masamune/transform/load_dimension_spec.rb