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,40 @@
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 'delegate'
24
+ require 'forwardable'
25
+
26
+ module Masamune
27
+ module HasEnvironment
28
+ extend Forwardable
29
+
30
+ def environment
31
+ @environment ||= Masamune::Environment.new
32
+ end
33
+
34
+ def environment=(environment)
35
+ @environment = environment
36
+ end
37
+
38
+ def_delegators :environment, :configure, :configuration, :with_exclusive_lock, :logger, :log_file_name, :filesystem, :filesystem=, :catalog, :trace, :console, :hive_helper, :postgres_helper
39
+ end
40
+ end
@@ -0,0 +1,27 @@
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
24
+ module Helpers
25
+ require 'masamune/helpers/postgres'
26
+ end
27
+ end
@@ -0,0 +1,84 @@
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 'masamune/has_environment'
24
+ require 'masamune/actions/postgres'
25
+
26
+ module Masamune::Helpers
27
+ class Postgres
28
+ include Masamune::HasEnvironment
29
+ include Masamune::Actions::Postgres
30
+ include Masamune::Actions::PostgresAdmin
31
+
32
+ def initialize(environment)
33
+ self.environment = environment
34
+ clear!
35
+ end
36
+
37
+ def clear!
38
+ @cache = {}
39
+ end
40
+
41
+ def database_exists?
42
+ postgres(exec: 'SELECT version();', fail_fast: false).success?
43
+ end
44
+
45
+ def table_exists?(table)
46
+ return unless database_exists?
47
+ tables.include?(table)
48
+ end
49
+
50
+ def table_last_modified_at(table, options = {})
51
+ column = options[:last_modified_at]
52
+ return unless column
53
+ return unless table_exists?(table)
54
+ update_table_last_modified_at(table, column)
55
+ @cache[table]
56
+ end
57
+
58
+ def tables
59
+ update_tables
60
+ @cache.keys
61
+ end
62
+
63
+ private
64
+
65
+ def update_tables
66
+ return unless @cache.empty?
67
+ postgres(exec: 'SELECT table_name FROM information_schema.tables;', tuple_output: true) do |line|
68
+ table = line.strip
69
+ next if table =~ /\Apg_/
70
+ @cache[table] ||= nil
71
+ end
72
+ end
73
+
74
+ def update_table_last_modified_at(table, column)
75
+ return if @cache[table].present?
76
+ postgres(exec: "SELECT MAX(#{column}) FROM #{table};", tuple_output: true) do |line|
77
+ begin
78
+ @cache[table] = Time.parse(line.strip).at_beginning_of_minute.utc
79
+ rescue ArgumentError
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,33 @@
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
+ class IO
24
+ def wait_readable(timeout = 0)
25
+ rs, ws = IO.select([self], [], [], timeout)
26
+ rs && rs[0]
27
+ end unless IO.method_defined?(:wait_readable)
28
+
29
+ def wait_writable(timeout = 0)
30
+ rs, ws = IO.select([], [self], [], timeout)
31
+ ws && ws[0]
32
+ end unless IO.method_defined?(:wait_writable)
33
+ end
@@ -0,0 +1,53 @@
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 'active_support/concern'
24
+
25
+ module Masamune
26
+ module LastElement
27
+ extend ActiveSupport::Concern
28
+
29
+ def last_element(method, *args)
30
+ instance = send(method, *args)
31
+ case instance
32
+ when Array
33
+ instance.map { |elem| [elem, elem == instance.last] }
34
+ when Hash
35
+ instance.map { |key, value| [key, value, key == instance.keys.last] }
36
+ end
37
+ end
38
+
39
+ module ClassMethods
40
+ def method_with_last_element(method)
41
+ self.class_eval do
42
+ new_method = "#{method}_with_last_element"
43
+ old_method = "#{method}_without_last_element"
44
+ alias_method old_method, method
45
+ define_method(new_method) do |*args, &block|
46
+ last_element(old_method, *args)
47
+ end
48
+ alias_method method, new_method
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,41 @@
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
+ # FIXME refactor as Command
24
+ module Masamune
25
+ class MethodLogger < SimpleDelegator
26
+ def initialize(target, *methods)
27
+ super target
28
+ @target = target
29
+ @methods = methods
30
+ end
31
+
32
+ def method_missing(method_name, *args, &block)
33
+ @target.environment.console("#{method_name} with #{args.join(' ')}") if @methods.include?(method_name)
34
+ if @target.respond_to?(method_name)
35
+ @target.__send__(method_name, *args, &block)
36
+ else
37
+ super
38
+ end
39
+ end
40
+ end
41
+ end
@@ -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
+ # From: http://stackoverflow.com/a/6407200
24
+ module Masamune
25
+ class MultiIO
26
+ def initialize(*targets)
27
+ @targets = targets
28
+ @targets.each { |t| t.sync = true }
29
+ end
30
+
31
+ def write(*args)
32
+ @targets.each { |t| t.write(*args) }
33
+ end
34
+
35
+ def close
36
+ @targets.each(&:close)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,36 @@
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
24
+ module Schema
25
+ require 'masamune/schema/catalog'
26
+ require 'masamune/schema/store'
27
+ require 'masamune/schema/table'
28
+ require 'masamune/schema/table_reference'
29
+ require 'masamune/schema/dimension'
30
+ require 'masamune/schema/fact'
31
+ require 'masamune/schema/column'
32
+ require 'masamune/schema/row'
33
+ require 'masamune/schema/event'
34
+ require 'masamune/schema/map'
35
+ end
36
+ end
@@ -0,0 +1,233 @@
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 'active_support/core_ext/hash'
24
+
25
+ require 'masamune/schema/store'
26
+
27
+ module Masamune::Schema
28
+ class Catalog
29
+ include Masamune::HasEnvironment
30
+
31
+ class HasMap < SimpleDelegator
32
+ attr_accessor :maps
33
+
34
+ def initialize(*args)
35
+ super
36
+ @maps = {}
37
+ end
38
+
39
+ def map(options = {})
40
+ self.maps[options[:to]]
41
+ end
42
+ end
43
+
44
+ class HasFormat < SimpleDelegator
45
+ def initialize(store, options = {})
46
+ super store
47
+ @options = options
48
+ end
49
+
50
+ def format
51
+ @options.key?(:format) ? @options[:format] : __getobj__.format
52
+ end
53
+
54
+ def json_encoding
55
+ @options.key?(:json_encoding) ? @options[:json_encoding] : __getobj__.json_encoding
56
+ end
57
+
58
+ def headers
59
+ @options.key?(:headers) ? @options[:headers] : __getobj__.headers
60
+ end
61
+ end
62
+
63
+ class Context < SimpleDelegator
64
+ attr_accessor :options
65
+
66
+ def initialize(store, options = {})
67
+ super store
68
+ @store = store
69
+ @options = Hash.new { |h,k| h[k] = [] }
70
+ @options.merge!(store: @store)
71
+ @options.merge!(options)
72
+ end
73
+
74
+ def push(options = {})
75
+ @prev_options = @options.dup
76
+ @options.merge!(options)
77
+ end
78
+
79
+ def pop
80
+ @options = @prev_options
81
+ end
82
+ end
83
+
84
+ def initialize(environment)
85
+ self.environment = environment
86
+ @stores = Hash.new { |h,k| h[k] = Masamune::Schema::Store.new(environment, type: k) }
87
+ @context = nil
88
+ end
89
+
90
+ def clear!
91
+ @stores.clear
92
+ end
93
+
94
+ def schema(*args, &block)
95
+ options = args.last.is_a?(Hash) ? args.pop : {}
96
+ raise ArgumentError, 'schema store arguments required' unless args.any?
97
+ stores = args.map(&:to_sym)
98
+ stores.each do |id|
99
+ begin
100
+ @context = Context.new(@stores[id], options)
101
+ instance_eval &block
102
+ ensure
103
+ @context = nil
104
+ end
105
+ end
106
+ end
107
+
108
+ Masamune::Schema::Store.types.each do |store|
109
+ define_method(store) do
110
+ @stores[store]
111
+ end
112
+ end
113
+
114
+ def [](store_id)
115
+ @stores[store_id.to_sym]
116
+ end
117
+
118
+ def table(id, options = {}, &block)
119
+ @context.push(options)
120
+ yield if block_given?
121
+ @context.tables[id] ||= Masamune::Schema::Table.new(@context.options.merge(id: id))
122
+ @context.references[id] ||= Masamune::Schema::TableReference.new(@context.tables[id])
123
+ ensure
124
+ @context.pop
125
+ end
126
+
127
+ def dimension(id, options = {}, &block)
128
+ @context.push(options)
129
+ yield if block_given?
130
+ @context.dimensions[id] ||= Masamune::Schema::Dimension.new(@context.options.merge(id: id))
131
+ @context.references[id] ||= Masamune::Schema::TableReference.new(@context.dimensions[id])
132
+ ensure
133
+ @context.pop
134
+ end
135
+
136
+ def column(id, options = {}, &block)
137
+ @context.options[:columns] << dereference_column(id, options)
138
+ end
139
+
140
+ # FIXME: references should not be ambiguous, e.g. references :user, should be references :user_dimension
141
+ def references(id, options = {})
142
+ table = @context.tables[id] || @context.dimensions[id]
143
+ table ||= Masamune::Schema::Dimension.new(id: id, type: :mini) if options[:degenerate]
144
+ reference = Masamune::Schema::TableReference.new(table, options.reverse_merge(denormalize: table.implicit))
145
+ @context.references[reference.id] = reference
146
+ @context.options[:references] << reference
147
+ end
148
+
149
+ def row(options)
150
+ attributes = options.delete(:attributes) || {}
151
+ attributes[:values] = options
152
+ @context.options[:rows] << Masamune::Schema::Row.new(attributes)
153
+ end
154
+
155
+ def fact(id, options = {}, &block)
156
+ @context.push(options)
157
+ grain = Array.wrap(options.delete(:grain) || [])
158
+ fact_attributes(grain).each do |attributes|
159
+ yield if block_given?
160
+ table = Masamune::Schema::Fact.new(@context.options.merge(id: id).merge(attributes))
161
+ @context.facts[table.id] ||= table
162
+ end
163
+ ensure
164
+ @context.pop
165
+ end
166
+
167
+ def partition(id, options = {}, &block)
168
+ @context.options[:columns] << Masamune::Schema::Column.new(options.merge(id: id, partition: true))
169
+ end
170
+
171
+ def measure(id, options = {}, &block)
172
+ @context.options[:columns] << Masamune::Schema::Column.new(options.merge(id: id, measure: true))
173
+ end
174
+
175
+ def file(id, options = {}, &block)
176
+ format_options = options.extract!(:format, :headers)
177
+ @context.push(options)
178
+ yield if block_given?
179
+ store = HasFormat.new(@context, format_options)
180
+ @context.files[id] = HasMap.new Masamune::Schema::Table.new(@context.options.merge(id: id, type: :stage, store: store))
181
+ ensure
182
+ @context.pop
183
+ end
184
+
185
+ def event(id, options = {}, &block)
186
+ @context.push(options)
187
+ yield if block_given?
188
+ @context.events[id] = HasMap.new Masamune::Schema::Event.new(@context.options.merge(id: id))
189
+ ensure
190
+ @context.pop
191
+ end
192
+
193
+ def attribute(id, options = {}, &block)
194
+ @context.options[:attributes] << Masamune::Schema::Event::Attribute.new(options.merge(id: id))
195
+ end
196
+
197
+ def map(options = {}, &block)
198
+ raise ArgumentError, "invalid map, from: is missing" unless options.is_a?(Hash)
199
+ from, to = options.delete(:from), options.delete(:to)
200
+ raise ArgumentError, "invalid map, from: is missing" unless from && from.try(:id)
201
+ raise ArgumentError, "invalid map from: '#{from.id}', to: is missing" unless to
202
+ @context.push(options)
203
+ @context.options[:function] = block.to_proc
204
+ from.maps[to] ||= Masamune::Schema::Map.new(@context.options.merge(source: from, target: to))
205
+ ensure
206
+ @context.pop
207
+ end
208
+
209
+ def load(file)
210
+ case file
211
+ when /\.rb\Z/
212
+ instance_eval(File.read(file), file)
213
+ when /\.psql\Z/
214
+ @stores[:postgres].extra << file
215
+ when /\.hql\Z/
216
+ @stores[:hive].extra << file
217
+ end
218
+ end
219
+
220
+ private
221
+
222
+ def dereference_column(id, options = {})
223
+ store_id = id.split(/\./).reverse.last.try(:to_sym)
224
+ context = store_id && @stores.key?(store_id) ? @stores[store_id] : @context
225
+ context.dereference_column(id, options)
226
+ end
227
+
228
+ def fact_attributes(grain = [])
229
+ return [{}] unless grain.any?
230
+ grain.map { |x| { grain: x } }
231
+ end
232
+ end
233
+ end