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,527 @@
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 'json'
24
+
25
+ module Masamune::Schema
26
+ class Column
27
+ DEFAULT_ATTRIBUTES =
28
+ {
29
+ id: nil,
30
+ type: :integer,
31
+ sub_type: nil,
32
+ array: false,
33
+ values: [],
34
+ null: false,
35
+ strict: true,
36
+ default: nil,
37
+ auto: false,
38
+ index: Set.new,
39
+ unique: Set.new,
40
+ ignore: false,
41
+ sequence_offset: 1,
42
+ surrogate_key: false,
43
+ natural_key: false,
44
+ measure: false,
45
+ partition: false,
46
+ aggregate: nil,
47
+ reference: nil,
48
+ parent: nil,
49
+ debug: false
50
+ }
51
+
52
+ DEFAULT_ATTRIBUTES.keys.each do |attr|
53
+ attr_accessor attr
54
+ end
55
+
56
+ def initialize(opts = {})
57
+ opts.symbolize_keys!
58
+ raise ArgumentError, 'required parameter id: missing' unless opts.key?(:id)
59
+ DEFAULT_ATTRIBUTES.merge(opts).each do |name, value|
60
+ public_send("#{name}=", value)
61
+ end
62
+ end
63
+
64
+ def id=(id)
65
+ @id = id.to_sym
66
+ end
67
+
68
+ def name
69
+ if reference && reference.columns.include?(id)
70
+ [reference.label, reference.name, id].compact.join('_').to_sym
71
+ else
72
+ id
73
+ end
74
+ end
75
+
76
+ def default
77
+ return @default unless @default.nil?
78
+ case type
79
+ when :uuid
80
+ 'uuid_generate_v4()'
81
+ when :sequence
82
+ "nextval('#{sequence_id}')"
83
+ when :enum
84
+ values.first
85
+ end
86
+ end
87
+
88
+ def index=(value)
89
+ @index ||= Set.new
90
+ @index.clear
91
+ @index +=
92
+ case value
93
+ when true
94
+ [id]
95
+ when false
96
+ []
97
+ when String, Symbol
98
+ [value.to_sym]
99
+ when Array, Set
100
+ value.map(&:to_sym)
101
+ else
102
+ raise ArgumentError
103
+ end
104
+ end
105
+
106
+ def unique
107
+ self.unique = 'natural' if natural_key
108
+ @unique
109
+ end
110
+
111
+ def unique=(value)
112
+ @unique ||= Set.new
113
+ @unique.clear
114
+ @unique +=
115
+ case value
116
+ when true
117
+ [id]
118
+ when false
119
+ []
120
+ when String, Symbol
121
+ [value.to_sym]
122
+ when Array, Set
123
+ value.map(&:to_sym)
124
+ else
125
+ raise ArgumentError
126
+ end
127
+ end
128
+
129
+ def foreign_key_name
130
+ "#{reference.name}.#{@id}".to_sym if reference
131
+ end
132
+
133
+ def compact_name
134
+ if reference
135
+ # XXX once columns only reference columns, this can be cleaned up
136
+ if @id == reference.surrogate_key.reference_name(reference.label)
137
+ "#{reference.id}.#{reference.surrogate_key.id}".to_sym
138
+ else
139
+ "#{reference.id}.#{@id}".to_sym
140
+ end
141
+ else
142
+ @id
143
+ end
144
+ end
145
+
146
+ def qualified_name(label = nil)
147
+ [label, (parent ? "#{parent.name}.#{name}" : name)].compact.join('_').to_sym
148
+ end
149
+
150
+ def reference_name(label = nil)
151
+ qualified_name(label).to_s.gsub(/\./, '_').to_sym
152
+ end
153
+
154
+ def sql_type(for_surrogate_key = false)
155
+ elem =
156
+ case type
157
+ when :integer
158
+ for_surrogate_key ? 'SERIAL' : 'INTEGER'
159
+ when :money
160
+ 'MONEY'
161
+ when :string
162
+ 'VARCHAR'
163
+ when :uuid
164
+ 'UUID'
165
+ when :date
166
+ 'DATE'
167
+ when :timestamp
168
+ 'TIMESTAMP'
169
+ when :boolean
170
+ 'BOOLEAN'
171
+ when :sequence
172
+ 'INTEGER'
173
+ when :enum
174
+ "#{sub_type || id}_TYPE".upcase
175
+ when :key_value
176
+ if parent.type == :stage && !parent.inherit
177
+ 'JSON'
178
+ else
179
+ 'HSTORE'
180
+ end
181
+ when :json, :yaml
182
+ 'JSON'
183
+ end
184
+ array_value? ? "#{elem}[]" : elem
185
+ end
186
+
187
+ def hql_type
188
+ elem =
189
+ case type
190
+ when :integer
191
+ 'INT'
192
+ when :string
193
+ 'STRING'
194
+ else
195
+ sql_type
196
+ end
197
+ array_value? ? "ARRAY<#{elem}>" : elem
198
+ end
199
+
200
+ def sql_value(value)
201
+ return value if sql_function?(value)
202
+ return 'NULL' if value == :null
203
+ case type
204
+ when :boolean
205
+ value ? 'TRUE' : 'FALSE'
206
+ when :string
207
+ "'#{value}'"
208
+ when :enum
209
+ "'#{value}'::#{sql_type}"
210
+ else
211
+ value
212
+ end
213
+ end
214
+
215
+ def csv_value(value)
216
+ return value if sql_function?(value)
217
+ return csv_array(value) if array_value?
218
+ return nil if value.nil?
219
+ case type
220
+ when :boolean
221
+ value ? 'TRUE' : (hive_encoding? ? nil : 'FALSE')
222
+ when :yaml
223
+ value.to_hash.to_yaml
224
+ when :json, :key_value
225
+ value.to_hash.to_json
226
+ when :date
227
+ value.to_s
228
+ when :timestamp
229
+ value.to_time.utc.iso8601(3)
230
+ when :string
231
+ value.empty? ? nil : value
232
+ else
233
+ value
234
+ end
235
+ rescue
236
+ raise ArgumentError, "Could not coerce '#{value}' into :#{type} for column '#{name}'"
237
+ end
238
+
239
+ def ruby_value(value, recursive = true)
240
+ value = nil if null_value?(value)
241
+ return value if sql_function?(value)
242
+ return ruby_array(value) if recursive && array_value?
243
+ case type
244
+ when :boolean
245
+ case value
246
+ when false, 0, '0', "'0'", /\Afalse\z/i
247
+ false
248
+ when true, 1, '1', "'1'", /\Atrue\z/i
249
+ true
250
+ end
251
+ when :date
252
+ case value
253
+ when Date
254
+ value
255
+ when String
256
+ Date.parse(value.to_s)
257
+ when nil
258
+ nil
259
+ end
260
+ when :timestamp
261
+ case value
262
+ when Time
263
+ value
264
+ when Date, DateTime
265
+ value.to_time
266
+ when String
267
+ if value =~ /\A\d+\z/
268
+ Time.at(value.to_i)
269
+ else
270
+ Time.parse(value)
271
+ end
272
+ when Integer
273
+ Time.at(value)
274
+ when nil
275
+ nil
276
+ end
277
+ when :integer
278
+ value.nil? ? nil : value.to_i
279
+ when :yaml
280
+ case value
281
+ when Hash
282
+ value
283
+ when String
284
+ ruby_key_value(YAML.load(value))
285
+ when nil
286
+ {}
287
+ end
288
+ when :json
289
+ case value
290
+ when Hash
291
+ value
292
+ when String
293
+ ruby_key_value(JSON.load(value))
294
+ when nil
295
+ {}
296
+ end
297
+ when :string
298
+ value.to_s
299
+ else
300
+ value
301
+ end
302
+ rescue
303
+ raise ArgumentError, "Could not coerce '#{value}' into :#{type} for column '#{name}'"
304
+ end
305
+
306
+ def default_ruby_value
307
+ return [] if array_value?
308
+ return {} if hash_value?
309
+ case type
310
+ when :date
311
+ Date.new(0)
312
+ when :timestamp
313
+ Time.new(0)
314
+ else
315
+ nil
316
+ end
317
+ end
318
+
319
+ def aggregate_value
320
+ return qualified_name unless aggregate
321
+ case aggregate
322
+ when :min
323
+ "MIN(#{qualified_name})"
324
+ when :max
325
+ "MAX(#{qualified_name})"
326
+ when :sum
327
+ "SUM(#{qualified_name})"
328
+ when :average
329
+ "AVG(#{qualified_name})"
330
+ end
331
+ end
332
+
333
+ def null_value?(value)
334
+ if type == :json || array_value?
335
+ return true if value == 'NULL'
336
+ end
337
+ return false unless value
338
+ if hive_encoding?
339
+ value.to_s == '\N'
340
+ else
341
+ false
342
+ end
343
+ end
344
+
345
+ def hive_encoding?
346
+ if parent && parent.store
347
+ parent.store.type == :hive
348
+ else
349
+ false
350
+ end
351
+ end
352
+
353
+ def sql_function?(value)
354
+ value =~ /\(\)\Z/
355
+ end
356
+
357
+ def array_value?
358
+ !!(array || (reference && reference.respond_to?(:multiple) && reference.multiple))
359
+ end
360
+
361
+ def hash_value?
362
+ [:key_value, :yaml, :json].include?(type)
363
+ end
364
+
365
+ def as_psql
366
+ [name, sql_type(surrogate_key), *sql_constraints, reference_constraint, sql_default].compact.join(' ')
367
+ end
368
+
369
+ def as_hash
370
+ {id: id}.tap do |hash|
371
+ DEFAULT_ATTRIBUTES.keys.each do |attr|
372
+ hash[attr] = public_send(attr)
373
+ end
374
+ end
375
+ end
376
+
377
+ # TODO: Add ELEMENT REFERENCES
378
+ def reference_constraint
379
+ return if parent.temporary?
380
+ return if degenerate?
381
+ return if array_value?
382
+ if reference && reference.surrogate_key.type == type
383
+ "REFERENCES #{reference.name}(#{reference.surrogate_key.name})"
384
+ end
385
+ end
386
+
387
+ class << self
388
+ def dereference_column_name(name)
389
+ return unless name
390
+ if name.to_s =~ /\./
391
+ reference_name, column_name = name.to_s.split('.')
392
+ [reference_name.to_sym, column_name.to_sym]
393
+ else
394
+ [nil, name.to_sym]
395
+ end
396
+ end
397
+ end
398
+
399
+ def ==(other)
400
+ return false unless other
401
+ id == other.id &&
402
+ typecast?(other.type) &&
403
+ (!reference || reference.id == other.reference.try(:id) || reference.id == other.parent.try(:id)) &&
404
+ (!other.reference || other.reference.id == reference.try(:id) || other.reference.id == parent.try(:id))
405
+ end
406
+
407
+ def eql?(other)
408
+ self == other
409
+ end
410
+
411
+ def hash
412
+ [id, type].hash
413
+ end
414
+
415
+ def typecast?(other_type)
416
+ return true if type == other_type
417
+ case [type, other_type]
418
+ when [:key_value, :yaml]
419
+ true
420
+ when [:key_value, :json]
421
+ true
422
+ when [:yaml, :json]
423
+ true
424
+ else
425
+ false
426
+ end
427
+ end
428
+
429
+ def auto_reference
430
+ reference && reference.surrogate_key.auto && !reference.insert
431
+ end
432
+
433
+ # XXX hack to work around columns not being able to reference columns
434
+ def references?(other)
435
+ return false unless other
436
+ if reference && other.reference && reference.id == other.reference.id
437
+ true
438
+ elsif parent && other.parent && parent.id == other.parent.id
439
+ self == other
440
+ elsif parent && other.parent && other.parent.parent && parent.id == other.parent.parent.id
441
+ self == other
442
+ elsif reference && other.parent && reference.id == other.parent.id
443
+ self == other
444
+ elsif natural_key || other.natural_key
445
+ self == other
446
+ else
447
+ false
448
+ end
449
+ end
450
+
451
+ def degenerate?
452
+ reference && reference.respond_to?(:degenerate) && reference.degenerate
453
+ end
454
+
455
+ def adjacent
456
+ return unless reference
457
+ reference.columns[id]
458
+ end
459
+
460
+ def sequence_id
461
+ "#{reference_name}_seq" if type == :sequence
462
+ end
463
+
464
+ def required_value?
465
+ if reference
466
+ !(reference.null || reference.default)
467
+ else
468
+ surrogate_key || natural_key
469
+ end
470
+ end
471
+
472
+ private
473
+
474
+ def sql_constraints
475
+ [].tap do |constraints|
476
+ constraints << 'NOT NULL' unless null || surrogate_key || !strict || parent.temporary? || degenerate?
477
+ constraints << "PRIMARY KEY" if surrogate_key
478
+ end
479
+ end
480
+
481
+ def sql_default
482
+ return if default.nil?
483
+ return if !strict
484
+ "DEFAULT #{sql_value(default)}"
485
+ end
486
+
487
+ def ruby_array(value)
488
+ case value
489
+ when Array
490
+ value.map { |elem| ruby_value(elem, false) }
491
+ when String
492
+ Array.wrap(JSON.load(value)).map { |elem| ruby_value(elem, false) }
493
+ when nil
494
+ []
495
+ end
496
+ end
497
+
498
+ def ruby_key_value(hash)
499
+ case sub_type
500
+ when :boolean
501
+ Hash[hash.map { |key, value| ruby_boolean_key_value(key, value) }.compact]
502
+ else
503
+ hash
504
+ end
505
+ end
506
+
507
+ def ruby_boolean_key_value(key, value)
508
+ case value
509
+ when true, '1', 1
510
+ [key, true]
511
+ when false, '0', 0
512
+ [key, false]
513
+ end
514
+ end
515
+
516
+ def csv_array(value)
517
+ case value
518
+ when Array
519
+ ruby_value(value).to_json
520
+ when nil
521
+ [].to_json
522
+ else
523
+ [ruby_value(value, false)].to_json
524
+ end
525
+ end
526
+ end
527
+ end