masamune 0.11.0

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.
Files changed (185) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +54 -0
  4. data/Rakefile +15 -0
  5. data/bin/masamune-elastic-mapreduce +4 -0
  6. data/bin/masamune-hive +4 -0
  7. data/bin/masamune-psql +4 -0
  8. data/bin/masamune-shell +4 -0
  9. data/lib/masamune.rb +56 -0
  10. data/lib/masamune/accumulate.rb +60 -0
  11. data/lib/masamune/actions.rb +38 -0
  12. data/lib/masamune/actions/data_flow.rb +131 -0
  13. data/lib/masamune/actions/date_parse.rb +75 -0
  14. data/lib/masamune/actions/elastic_mapreduce.rb +68 -0
  15. data/lib/masamune/actions/execute.rb +52 -0
  16. data/lib/masamune/actions/filesystem.rb +37 -0
  17. data/lib/masamune/actions/hadoop_filesystem.rb +40 -0
  18. data/lib/masamune/actions/hadoop_streaming.rb +41 -0
  19. data/lib/masamune/actions/hive.rb +74 -0
  20. data/lib/masamune/actions/postgres.rb +76 -0
  21. data/lib/masamune/actions/postgres_admin.rb +34 -0
  22. data/lib/masamune/actions/s3cmd.rb +44 -0
  23. data/lib/masamune/actions/transform.rb +89 -0
  24. data/lib/masamune/after_initialize_callbacks.rb +55 -0
  25. data/lib/masamune/cached_filesystem.rb +110 -0
  26. data/lib/masamune/commands.rb +37 -0
  27. data/lib/masamune/commands/elastic_mapreduce.rb +119 -0
  28. data/lib/masamune/commands/hadoop_filesystem.rb +57 -0
  29. data/lib/masamune/commands/hadoop_streaming.rb +116 -0
  30. data/lib/masamune/commands/hive.rb +178 -0
  31. data/lib/masamune/commands/interactive.rb +37 -0
  32. data/lib/masamune/commands/postgres.rb +128 -0
  33. data/lib/masamune/commands/postgres_admin.rb +72 -0
  34. data/lib/masamune/commands/postgres_common.rb +33 -0
  35. data/lib/masamune/commands/retry_with_backoff.rb +60 -0
  36. data/lib/masamune/commands/s3cmd.rb +70 -0
  37. data/lib/masamune/commands/shell.rb +202 -0
  38. data/lib/masamune/configuration.rb +195 -0
  39. data/lib/masamune/data_plan.rb +31 -0
  40. data/lib/masamune/data_plan/builder.rb +66 -0
  41. data/lib/masamune/data_plan/elem.rb +190 -0
  42. data/lib/masamune/data_plan/engine.rb +162 -0
  43. data/lib/masamune/data_plan/rule.rb +292 -0
  44. data/lib/masamune/data_plan/set.rb +176 -0
  45. data/lib/masamune/environment.rb +164 -0
  46. data/lib/masamune/filesystem.rb +567 -0
  47. data/lib/masamune/has_environment.rb +40 -0
  48. data/lib/masamune/helpers.rb +27 -0
  49. data/lib/masamune/helpers/postgres.rb +84 -0
  50. data/lib/masamune/io.rb +33 -0
  51. data/lib/masamune/last_element.rb +53 -0
  52. data/lib/masamune/method_logger.rb +41 -0
  53. data/lib/masamune/multi_io.rb +39 -0
  54. data/lib/masamune/schema.rb +36 -0
  55. data/lib/masamune/schema/catalog.rb +233 -0
  56. data/lib/masamune/schema/column.rb +527 -0
  57. data/lib/masamune/schema/dimension.rb +133 -0
  58. data/lib/masamune/schema/event.rb +121 -0
  59. data/lib/masamune/schema/fact.rb +133 -0
  60. data/lib/masamune/schema/map.rb +265 -0
  61. data/lib/masamune/schema/row.rb +133 -0
  62. data/lib/masamune/schema/store.rb +115 -0
  63. data/lib/masamune/schema/table.rb +308 -0
  64. data/lib/masamune/schema/table_reference.rb +76 -0
  65. data/lib/masamune/spec_helper.rb +23 -0
  66. data/lib/masamune/string_format.rb +34 -0
  67. data/lib/masamune/tasks/elastic_mapreduce_thor.rb +60 -0
  68. data/lib/masamune/tasks/hive_thor.rb +55 -0
  69. data/lib/masamune/tasks/postgres_thor.rb +47 -0
  70. data/lib/masamune/tasks/shell_thor.rb +63 -0
  71. data/lib/masamune/template.rb +77 -0
  72. data/lib/masamune/thor.rb +186 -0
  73. data/lib/masamune/thor_loader.rb +38 -0
  74. data/lib/masamune/topological_hash.rb +34 -0
  75. data/lib/masamune/transform.rb +47 -0
  76. data/lib/masamune/transform/bulk_upsert.psql.erb +64 -0
  77. data/lib/masamune/transform/bulk_upsert.rb +52 -0
  78. data/lib/masamune/transform/consolidate_dimension.rb +54 -0
  79. data/lib/masamune/transform/deduplicate_dimension.psql.erb +52 -0
  80. data/lib/masamune/transform/deduplicate_dimension.rb +53 -0
  81. data/lib/masamune/transform/define_event_view.hql.erb +51 -0
  82. data/lib/masamune/transform/define_event_view.rb +60 -0
  83. data/lib/masamune/transform/define_index.psql.erb +34 -0
  84. data/lib/masamune/transform/define_schema.hql.erb +23 -0
  85. data/lib/masamune/transform/define_schema.psql.erb +79 -0
  86. data/lib/masamune/transform/define_schema.rb +56 -0
  87. data/lib/masamune/transform/define_table.hql.erb +34 -0
  88. data/lib/masamune/transform/define_table.psql.erb +95 -0
  89. data/lib/masamune/transform/define_table.rb +40 -0
  90. data/lib/masamune/transform/define_unique.psql.erb +30 -0
  91. data/lib/masamune/transform/insert_reference_values.psql.erb +43 -0
  92. data/lib/masamune/transform/insert_reference_values.rb +64 -0
  93. data/lib/masamune/transform/load_dimension.rb +47 -0
  94. data/lib/masamune/transform/load_fact.rb +45 -0
  95. data/lib/masamune/transform/operator.rb +96 -0
  96. data/lib/masamune/transform/relabel_dimension.psql.erb +76 -0
  97. data/lib/masamune/transform/relabel_dimension.rb +39 -0
  98. data/lib/masamune/transform/rollup_fact.psql.erb +79 -0
  99. data/lib/masamune/transform/rollup_fact.rb +149 -0
  100. data/lib/masamune/transform/snapshot_dimension.psql.erb +75 -0
  101. data/lib/masamune/transform/snapshot_dimension.rb +74 -0
  102. data/lib/masamune/transform/stage_dimension.psql.erb +39 -0
  103. data/lib/masamune/transform/stage_dimension.rb +83 -0
  104. data/lib/masamune/transform/stage_fact.psql.erb +80 -0
  105. data/lib/masamune/transform/stage_fact.rb +111 -0
  106. data/lib/masamune/version.rb +25 -0
  107. data/spec/fixtures/aggregate.sql.erb +25 -0
  108. data/spec/fixtures/comment.sql.erb +27 -0
  109. data/spec/fixtures/invalid.sql.erb +23 -0
  110. data/spec/fixtures/relative.sql.erb +23 -0
  111. data/spec/fixtures/simple.sql.erb +28 -0
  112. data/spec/fixtures/whitespace.sql.erb +30 -0
  113. data/spec/masamune/actions/elastic_mapreduce_spec.rb +108 -0
  114. data/spec/masamune/actions/execute_spec.rb +50 -0
  115. data/spec/masamune/actions/hadoop_filesystem_spec.rb +44 -0
  116. data/spec/masamune/actions/hadoop_streaming_spec.rb +74 -0
  117. data/spec/masamune/actions/hive_spec.rb +117 -0
  118. data/spec/masamune/actions/postgres_admin_spec.rb +58 -0
  119. data/spec/masamune/actions/postgres_spec.rb +134 -0
  120. data/spec/masamune/actions/s3cmd_spec.rb +44 -0
  121. data/spec/masamune/actions/transform_spec.rb +144 -0
  122. data/spec/masamune/after_initialization_callbacks_spec.rb +61 -0
  123. data/spec/masamune/cached_filesystem_spec.rb +167 -0
  124. data/spec/masamune/commands/hadoop_filesystem_spec.rb +50 -0
  125. data/spec/masamune/commands/hadoop_streaming_spec.rb +106 -0
  126. data/spec/masamune/commands/hive_spec.rb +117 -0
  127. data/spec/masamune/commands/postgres_admin_spec.rb +69 -0
  128. data/spec/masamune/commands/postgres_spec.rb +100 -0
  129. data/spec/masamune/commands/retry_with_backoff_spec.rb +116 -0
  130. data/spec/masamune/commands/s3cmd_spec.rb +50 -0
  131. data/spec/masamune/commands/shell_spec.rb +101 -0
  132. data/spec/masamune/configuration_spec.rb +102 -0
  133. data/spec/masamune/data_plan/builder_spec.rb +91 -0
  134. data/spec/masamune/data_plan/elem_spec.rb +102 -0
  135. data/spec/masamune/data_plan/engine_spec.rb +356 -0
  136. data/spec/masamune/data_plan/rule_spec.rb +407 -0
  137. data/spec/masamune/data_plan/set_spec.rb +517 -0
  138. data/spec/masamune/environment_spec.rb +65 -0
  139. data/spec/masamune/filesystem_spec.rb +1421 -0
  140. data/spec/masamune/helpers/postgres_spec.rb +95 -0
  141. data/spec/masamune/schema/catalog_spec.rb +613 -0
  142. data/spec/masamune/schema/column_spec.rb +696 -0
  143. data/spec/masamune/schema/dimension_spec.rb +137 -0
  144. data/spec/masamune/schema/event_spec.rb +75 -0
  145. data/spec/masamune/schema/fact_spec.rb +117 -0
  146. data/spec/masamune/schema/map_spec.rb +593 -0
  147. data/spec/masamune/schema/row_spec.rb +28 -0
  148. data/spec/masamune/schema/store_spec.rb +49 -0
  149. data/spec/masamune/schema/table_spec.rb +395 -0
  150. data/spec/masamune/string_format_spec.rb +60 -0
  151. data/spec/masamune/tasks/elastic_mapreduce_thor_spec.rb +57 -0
  152. data/spec/masamune/tasks/hive_thor_spec.rb +75 -0
  153. data/spec/masamune/tasks/postgres_thor_spec.rb +42 -0
  154. data/spec/masamune/tasks/shell_thor_spec.rb +51 -0
  155. data/spec/masamune/template_spec.rb +77 -0
  156. data/spec/masamune/thor_spec.rb +238 -0
  157. data/spec/masamune/transform/bulk_upsert.dimension_spec.rb +200 -0
  158. data/spec/masamune/transform/consolidate_dimension_spec.rb +62 -0
  159. data/spec/masamune/transform/deduplicate_dimension_spec.rb +84 -0
  160. data/spec/masamune/transform/define_event_view_spec.rb +84 -0
  161. data/spec/masamune/transform/define_schema_spec.rb +83 -0
  162. data/spec/masamune/transform/define_table.dimension_spec.rb +306 -0
  163. data/spec/masamune/transform/define_table.fact_spec.rb +291 -0
  164. data/spec/masamune/transform/define_table.table_spec.rb +525 -0
  165. data/spec/masamune/transform/insert_reference_values.dimension_spec.rb +111 -0
  166. data/spec/masamune/transform/insert_reference_values.fact_spec.rb +149 -0
  167. data/spec/masamune/transform/load_dimension_spec.rb +76 -0
  168. data/spec/masamune/transform/load_fact_spec.rb +89 -0
  169. data/spec/masamune/transform/relabel_dimension_spec.rb +102 -0
  170. data/spec/masamune/transform/rollup_fact_spec.rb +333 -0
  171. data/spec/masamune/transform/snapshot_dimension_spec.rb +103 -0
  172. data/spec/masamune/transform/stage_dimension_spec.rb +115 -0
  173. data/spec/masamune/transform/stage_fact_spec.rb +204 -0
  174. data/spec/masamune_spec.rb +32 -0
  175. data/spec/spec_helper.rb +41 -0
  176. data/spec/support/masamune/example_group.rb +36 -0
  177. data/spec/support/masamune/mock_command.rb +99 -0
  178. data/spec/support/masamune/mock_delegate.rb +51 -0
  179. data/spec/support/masamune/mock_filesystem.rb +96 -0
  180. data/spec/support/masamune/thor_mute.rb +35 -0
  181. data/spec/support/rspec/example/action_example_group.rb +34 -0
  182. data/spec/support/rspec/example/task_example_group.rb +80 -0
  183. data/spec/support/rspec/example/transform_example_group.rb +36 -0
  184. data/spec/support/shared_examples/postgres_common_examples.rb +53 -0
  185. metadata +462 -0
@@ -0,0 +1,76 @@
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
+ BEGIN;
24
+ LOCK TABLE <%= target.name %> IN EXCLUSIVE MODE;
25
+
26
+ <%-# Relabel version column -%>
27
+ UPDATE <%= target.name %> SET version = NULL;
28
+
29
+ UPDATE
30
+ <%= target.name %>
31
+ SET
32
+ version = tmp.version
33
+ FROM
34
+ (
35
+ SELECT
36
+ id,
37
+ <%- target.window.each do |name| -%>
38
+ <%= name %>,
39
+ <%- end -%>
40
+ start_at,
41
+ rank() OVER (PARTITION BY <%= target.window.join(', ') %> ORDER BY start_at) AS version
42
+ FROM
43
+ <%= target.name %>
44
+ GROUP BY
45
+ <%= target.window(:id, :start_at).join(', ') %>
46
+ ) AS tmp
47
+ WHERE
48
+ <%= target.name %>.id = tmp.id
49
+ ;
50
+
51
+ <%-# Relabel end_at column -%>
52
+ UPDATE <%= target.name %> SET end_at = NULL;
53
+
54
+ UPDATE
55
+ <%= target.name %>
56
+ SET
57
+ end_at = tmp.end_at
58
+ FROM
59
+ (
60
+ SELECT
61
+ id,
62
+ start_at,
63
+ <%- target.window.each do |name| -%>
64
+ <%= name %>,
65
+ <%- end -%>
66
+ LEAD(start_at, 1) OVER (PARTITION BY <%= target.window.join(', ') %> ORDER BY start_at) AS end_at
67
+ FROM
68
+ <%= target.name %>
69
+ GROUP BY
70
+ <%= target.window(:id, :start_at).join(', ') %>
71
+ ) AS tmp
72
+ WHERE
73
+ <%= target.name %>.id = tmp.id
74
+ ;
75
+
76
+ COMMIT;
@@ -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
+ module Masamune::Transform
24
+ module RelabelDimension
25
+ extend ActiveSupport::Concern
26
+
27
+ def relabel_dimension(target)
28
+ Operator.new(__method__, target: target, presenters: { postgres: Postgres })
29
+ end
30
+
31
+ private
32
+
33
+ class Postgres < SimpleDelegator
34
+ def window(*extra)
35
+ (columns.values.select { |column| extra.delete(column.name) || column.natural_key || column.auto_reference }.map(&:name) + extra).uniq
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,79 @@
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
+ <%- target_stage = target.stage_table %>
24
+
25
+ BEGIN;
26
+
27
+ DROP TABLE IF EXISTS <%= target_stage.name %> CASCADE;
28
+ CREATE TABLE IF NOT EXISTS <%= target_stage.name %> (LIKE <%= target.parent.name %> INCLUDING ALL);
29
+
30
+ ALTER TABLE <%= target_stage.name %> ADD CONSTRAINT <%= target_stage.name %>_time_key_check <%= target_stage.constraints %>;
31
+ <%- target.foreign_key_columns.each do |column| -%>
32
+ ALTER TABLE <%= target_stage.name %> ADD CONSTRAINT <%= target_stage.name %>_<%= column.name %>_fkey FOREIGN KEY (<%= column.name %>) <%= column.reference_constraint %>;
33
+ <%- end -%>
34
+
35
+ INSERT INTO
36
+ <%= target_stage.name %> (<%= target.insert_columns(source).join(', ') %>)
37
+ SELECT
38
+ <%- target.insert_values(source).each do |value, last| -%>
39
+ <%= value %><%= ',' unless last %>
40
+ <%- end -%>
41
+ FROM
42
+ <%= source.name %>
43
+ <%- target.join_conditions(source).each do |table, conditions| -%>
44
+ JOIN
45
+ <%= table %>
46
+ ON
47
+ <%= conditions.join(" AND\n ") %>
48
+ <%- end -%>
49
+ GROUP BY
50
+ <%- target.group_by(source).each do |value, last| -%>
51
+ <%= value %><%= ',' unless last %>
52
+ <%- end -%>
53
+ ;
54
+
55
+ <%- target.index_columns.each do |column_names, unique| -%>
56
+ <%- index_name = "#{target_stage.name}_#{column_names.join('_')}_index" -%>
57
+ CREATE <%= unique ? 'UNIQUE INDEX' : 'INDEX' %> <%= index_name %> ON <%= target_stage.name %> (<%= column_names.join(', ') %>);
58
+ <%- end -%>
59
+
60
+ COMMIT;
61
+
62
+ BEGIN;
63
+
64
+ DROP TABLE IF EXISTS <%= target.name %>;
65
+ ALTER TABLE <%= target_stage.name %> RENAME TO <%= target.name %>;
66
+
67
+ ALTER TABLE <%= target.name %> INHERIT <%= target.parent.name %>;
68
+ ALTER TABLE <%= target.name %> ADD CONSTRAINT <%= target.name %>_time_key_check <%= target.constraints %> NOT VALID;
69
+ <%- target.foreign_key_columns.each do |column| -%>
70
+ ALTER TABLE <%= target.name %> ADD CONSTRAINT <%= target.name %>_<%= column.name %>_fkey FOREIGN KEY (<%= column.name %>) <%= column.reference_constraint %> NOT VALID;
71
+ <%- end -%>
72
+
73
+ <%- target.index_columns.each do |column_names, unique| -%>
74
+ <%- old_index_name = "#{target_stage.name}_#{column_names.join('_')}_index" -%>
75
+ <%- new_index_name = "#{target.name}_#{column_names.join('_')}_index" -%>
76
+ ALTER INDEX <%= old_index_name %> RENAME TO <%= new_index_name %>;
77
+ <%- end -%>
78
+
79
+ COMMIT;
@@ -0,0 +1,149 @@
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 RollupFact
25
+ extend ActiveSupport::Concern
26
+
27
+ def rollup_fact(source, target, date)
28
+ raise ArgumentError, "#{source.name} must have date_column to rollup" unless source.date_column
29
+ raise ArgumentError, "#{target.name} must have date_column to rollup" unless target.date_column
30
+ Operator.new __method__, source: source.partition_table(date), target: target.partition_table(date), presenters: { postgres: Postgres }
31
+ end
32
+
33
+ private
34
+
35
+ class Postgres < SimpleDelegator
36
+ include Masamune::LastElement
37
+
38
+ def insert_columns(source)
39
+ values = []
40
+ shared_columns(source).values.map do |columns|
41
+ column = columns.first
42
+ next if column.id == :last_modified_at
43
+ next if column.auto_reference
44
+ values << column.name
45
+ end
46
+ measures.each do |_ ,measure|
47
+ values << measure.name
48
+ end
49
+ values << time_key.name
50
+ values.compact
51
+ end
52
+
53
+ def insert_values(source)
54
+ values = []
55
+ values << "(#{first_date_surrogate_key})"
56
+ shared_columns(source).values.map do |columns|
57
+ column = columns.first
58
+ next unless column.reference
59
+ next if column.reference.type == :date
60
+ next if column.auto_reference
61
+ values << column.qualified_name
62
+ end
63
+ source.measures.each do |_ ,measure|
64
+ values << measure.aggregate_value
65
+ end
66
+ values << "(#{floor_time_key(source)})"
67
+ values
68
+ end
69
+ method_with_last_element :insert_values
70
+
71
+ def join_conditions(source)
72
+ {
73
+ source.date_column.reference.name => [
74
+ "#{source.date_column.reference.surrogate_key.qualified_name} = #{source.date_column.qualified_name}"
75
+ ]
76
+ }
77
+ end
78
+
79
+ def group_by(source)
80
+ group_by = []
81
+ group_by << date_column.reference.columns[rollup_key].qualified_name
82
+ shared_columns(source).values.map do |columns|
83
+ column = columns.first
84
+ next unless column.reference
85
+ next if column.reference.type == :date
86
+ next if column.auto_reference
87
+ group_by << column.qualified_name
88
+ end
89
+ group_by << "(#{floor_time_key(source)})" if grain == :hourly
90
+ group_by
91
+ end
92
+ method_with_last_element :group_by
93
+
94
+ private
95
+
96
+ def rollup_key
97
+ case grain
98
+ when :hourly
99
+ :date_epoch
100
+ when :daily
101
+ :date_epoch
102
+ when :monthly
103
+ :month_epoch
104
+ end
105
+ end
106
+
107
+ def date_key
108
+ :date_id
109
+ end
110
+
111
+ def first_date_surrogate_key
112
+ <<-EOS.gsub(/\s+/, ' ').strip
113
+ SELECT
114
+ #{date_column.reference.surrogate_key.name}
115
+ FROM
116
+ #{date_column.reference.name} d
117
+ WHERE
118
+ d.#{rollup_key} = #{date_column.reference.columns[rollup_key].qualified_name}
119
+ ORDER BY
120
+ d.#{date_key}
121
+ LIMIT 1
122
+ EOS
123
+ end
124
+
125
+ def floor_time_key(source)
126
+ case grain
127
+ when :hourly
128
+ "#{source.time_key.qualified_name} - (#{source.time_key.qualified_name} % #{1.hour.seconds})"
129
+ when :daily, :monthly
130
+ first_date_time_key
131
+ end
132
+ end
133
+
134
+ def first_date_time_key
135
+ <<-EOS.gsub(/\s+/, ' ').strip
136
+ SELECT
137
+ #{rollup_key}
138
+ FROM
139
+ #{date_column.reference.name} d
140
+ WHERE
141
+ d.#{rollup_key} = #{date_column.reference.columns[rollup_key].qualified_name}
142
+ ORDER BY
143
+ d.#{date_key}
144
+ LIMIT 1
145
+ EOS
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,75 @@
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
+ <%#
24
+ Consolidate complete events from partial events
25
+ For discussion on range and group constructions, see:
26
+ http://www.postgresql.org/message-id/CAGnEbohhKmW55oB0FpQd3naXBkwi74E=8DRZBGFjS-MeGpXLaA@mail.gmail.com
27
+ -%>
28
+ WITH ranges AS (
29
+ SELECT *,
30
+ CASE WHEN delta = 0
31
+ THEN 1 ELSE NULL END r
32
+ FROM <%= source.name %>
33
+ ), windows AS (
34
+ SELECT *,
35
+ SUM(r) OVER (ORDER BY <%= target.window("start_at #{order}", 'delta', 'source_uuid').join(', ') %>) window_id
36
+ FROM ranges
37
+ ), snapshot AS (
38
+ SELECT
39
+ <%- target.insert_view_values.each do |value| -%>
40
+ consolidated.<%= value %><%= ',' %>
41
+ <%- end -%>
42
+ consolidated.parent_id,
43
+ consolidated.record_id,
44
+ consolidated.start_at
45
+ FROM (
46
+ SELECT DISTINCT ON (<%= target.window('start_at').join(', ') %>)
47
+ FIRST_VALUE(id) OVER w AS parent_id,
48
+ FIRST_VALUE(start_at) OVER w AS parent_start_at,
49
+ id AS record_id,
50
+ <%- target.insert_values(window: 'w').each do |value, last| -%>
51
+ <%= value %><%= ',' %>
52
+ <%- end -%>
53
+ start_at AS start_at
54
+ FROM
55
+ windows
56
+ WINDOW w AS (PARTITION BY <%= target.window('window_id').join(', ') %> ORDER BY start_at <%= order %>)
57
+ ORDER BY <%= target.window("start_at #{order}", 'window_id').join(', ') %>
58
+ ) consolidated
59
+ WHERE
60
+ <%- target.insert_view_constraints.each do |constraint, last| -%>
61
+ consolidated.<%= constraint %><%= ' AND' unless last %>
62
+ <%- end -%>
63
+ )
64
+ INSERT INTO
65
+ <%= target.name %> (<%= target.insert_columns.join(', ') %>, parent_id, record_id, start_at)
66
+ SELECT
67
+ <%- target.insert_view_values.each do |value| -%>
68
+ <%= value %><%= ',' %>
69
+ <%- end -%>
70
+ parent_id,
71
+ record_id,
72
+ start_at
73
+ FROM
74
+ snapshot
75
+ ;
@@ -0,0 +1,74 @@
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 SnapshotDimension
25
+ extend ActiveSupport::Concern
26
+
27
+ def snapshot_dimension(source, target, order = 'DESC')
28
+ Operator.new(__method__, source: source, target: target, order: order, presenters: { postgres: Postgres })
29
+ end
30
+
31
+ private
32
+
33
+ class Postgres < SimpleDelegator
34
+ include Masamune::LastElement
35
+
36
+ def insert_columns(source = nil)
37
+ consolidated_columns.map { |_, column| column.name }
38
+ end
39
+
40
+ def insert_view_values
41
+ consolidated_columns.map { |_, column| column.name }
42
+ end
43
+
44
+ def insert_view_constraints
45
+ consolidated_columns.reject { |_, column| column.null }.map { |_, column| "#{column.name} IS NOT NULL" }
46
+ end
47
+ method_with_last_element :insert_view_constraints
48
+
49
+ def window(*extra)
50
+ (columns.values.select { |column| extra.delete(column.name) || column.natural_key || column.auto_reference }.map(&:name) + extra).uniq
51
+ end
52
+
53
+ def insert_values(opts = {})
54
+ window = opts[:window]
55
+ consolidated_columns.map do |_, column|
56
+ if column.natural_key
57
+ "#{column.name} AS #{column.name}"
58
+ elsif column.type == :key_value
59
+ "hstore_merge(#{column.name}_now) OVER #{window} - hstore_merge(#{column.name}_was) OVER #{window} AS #{column.name}"
60
+ else
61
+ "coalesce_merge(#{column.name}) OVER #{window} AS #{column.name}"
62
+ end
63
+ end
64
+ end
65
+ method_with_last_element :insert_values
66
+
67
+ private
68
+
69
+ def consolidated_columns
70
+ unreserved_columns.reject { |_, column| column.surrogate_key }
71
+ end
72
+ end
73
+ end
74
+ end