Class: Masamune::Schema::Column

Inherits:
Object
  • Object
show all
Defined in:
lib/masamune/schema/column.rb

Constant Summary collapse

DEFAULT_ATTRIBUTES =
{
  id:                  nil,
  type:                :integer,
  sub_type:            nil,
  array:               false,
  values:              [],
  null:                false,
  strict:              true,
  default:             nil,
  auto:                false,
  index:               Set.new,
  unique:              Set.new,
  ignore:              false,
  sequence_offset:     1,
  surrogate_key:       false,
  natural_key:         false,
  measure:             false,
  partition:           false,
  aggregate:           nil,
  reference:           nil,
  parent:              nil,
  debug:               false
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Column

Returns a new instance of Column.

Raises:

  • (ArgumentError)


56
57
58
59
60
61
62
# File 'lib/masamune/schema/column.rb', line 56

def initialize(opts = {})
  opts.symbolize_keys!
  raise ArgumentError, 'required parameter id: missing' unless opts.key?(:id)
  DEFAULT_ATTRIBUTES.merge(opts).each do |name, value|
    public_send("#{name}=", value)
  end
end

Class Method Details

.dereference_column_name(name) ⇒ Object



379
380
381
382
383
384
385
386
387
# File 'lib/masamune/schema/column.rb', line 379

def dereference_column_name(name)
  return unless name
  if name.to_s =~ /\./
    reference_name, column_name = name.to_s.split('.')
    [reference_name.to_sym, column_name.to_sym]
  else
    [nil, name.to_sym]
  end
end

Instance Method Details

#==(other) ⇒ Object



390
391
392
393
394
395
396
# File 'lib/masamune/schema/column.rb', line 390

def ==(other)
  return false unless other
  id == other.id &&
  typecast?(other.type) &&
  (!reference || reference.id == other.reference.try(:id) || reference.id == other.parent.try(:id)) &&
  (!other.reference || other.reference.id == reference.try(:id) || other.reference.id == parent.try(:id))
end

#adjacentObject



446
447
448
449
# File 'lib/masamune/schema/column.rb', line 446

def adjacent
  return unless reference
  reference.columns[id]
end

#aggregate_valueObject



316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/masamune/schema/column.rb', line 316

def aggregate_value
  return qualified_name unless aggregate
  case aggregate
  when :min
    "MIN(#{qualified_name})"
  when :max
    "MAX(#{qualified_name})"
  when :sum
    "SUM(#{qualified_name})"
  when :average
    "AVG(#{qualified_name})"
  end
end

#array_value?Boolean

Returns:

  • (Boolean)


354
355
356
# File 'lib/masamune/schema/column.rb', line 354

def array_value?
  (array || (reference && reference.respond_to?(:multiple) && reference.multiple)) == true
end

#as_hashObject



370
371
372
373
374
375
376
# File 'lib/masamune/schema/column.rb', line 370

def as_hash
  { id: id }.tap do |hash|
    DEFAULT_ATTRIBUTES.keys.each do |attr|
      hash[attr] = public_send(attr)
    end
  end
end

#as_hqlObject



366
367
368
# File 'lib/masamune/schema/column.rb', line 366

def as_hql
  [name, hql_type(surrogate_key)].compact.join(' ')
end

#as_psqlObject



362
363
364
# File 'lib/masamune/schema/column.rb', line 362

def as_psql
  [name, sql_type(surrogate_key), *sql_constraints, sql_default].compact.join(' ')
end

#auto_referenceObject



420
421
422
# File 'lib/masamune/schema/column.rb', line 420

def auto_reference
  reference && reference.surrogate_key.auto && !reference.insert
end

#compact_nameObject



124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/masamune/schema/column.rb', line 124

def compact_name
  if reference
    # XXX once columns only reference columns, this can be cleaned up
    if reference.surrogate_key && @id == reference.surrogate_key.reference_name(reference.label)
      "#{reference.id}.#{reference.surrogate_key.id}".to_sym
    else
      "#{reference.id}.#{@id}".to_sym
    end
  else
    @id
  end
end

#csv_value(value) ⇒ Object



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/masamune/schema/column.rb', line 206

def csv_value(value)
  return value if sql_function?(value)
  return csv_array(value) if array_value?
  return nil if value.nil?
  case type
  when :boolean
    if value
      'TRUE'
    else
      hive_encoding? ? nil : 'FALSE'
    end
  when :yaml
    value.to_hash.to_yaml
  when :json, :key_value
    value.to_hash.to_json
  when :date
    value.to_s
  when :timestamp
    value.to_time.utc.iso8601(3)
  when :string
    value.empty? ? nil : value
  else
    value
  end
rescue
  raise ArgumentError, "Could not coerce '#{value}' into :#{type} for column '#{name}'"
end

#defaultObject



76
77
78
79
80
81
82
83
84
# File 'lib/masamune/schema/column.rb', line 76

def default
  return @default unless @default.nil?
  case type
  when :uuid
    'uuid_generate_v4()'
  when :sequence
    "nextval('#{sequence_id}')"
  end
end

#default_ruby_valueObject



305
306
307
308
309
310
311
312
313
314
# File 'lib/masamune/schema/column.rb', line 305

def default_ruby_value
  return [] if array_value?
  return HashWithIndifferentAccess.new { |h, k| h[k] = HashWithIndifferentAccess.new(&h.default_proc) } if hash_value?
  case type
  when :date
    Date.new(0)
  when :timestamp
    Time.new(0)
  end
end

#degenerate?Boolean

Returns:

  • (Boolean)


442
443
444
# File 'lib/masamune/schema/column.rb', line 442

def degenerate?
  reference && reference.respond_to?(:degenerate) && reference.degenerate
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


398
399
400
# File 'lib/masamune/schema/column.rb', line 398

def eql?(other)
  self == other
end

#foreign_key_nameObject



120
121
122
# File 'lib/masamune/schema/column.rb', line 120

def foreign_key_name
  "#{[reference.label, reference.name].compact.join('_')}.#{@id}".to_sym if reference
end

#hashObject



402
403
404
# File 'lib/masamune/schema/column.rb', line 402

def hash
  [id, type].hash
end

#hash_value?Boolean

Returns:

  • (Boolean)


358
359
360
# File 'lib/masamune/schema/column.rb', line 358

def hash_value?
  i[key_value yaml json].include?(type)
end

#hive_encoding?Boolean

Returns:

  • (Boolean)


342
343
344
345
346
347
348
# File 'lib/masamune/schema/column.rb', line 342

def hive_encoding?
  if parent && parent.store
    parent.store.type == :hive
  else
    false
  end
end

#hql_type(for_surrogate_key = false) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/masamune/schema/column.rb', line 178

def hql_type(for_surrogate_key = false)
  elem =
  case type
  when :integer
    for_surrogate_key ? 'STRING' : 'INT'
  when :string, :enum, :key_value, :timestamp
    'STRING'
  else
    sql_type
  end
  array_value? ? "ARRAY<#{elem}>" : elem
end

#id=(id) ⇒ Object



64
65
66
# File 'lib/masamune/schema/column.rb', line 64

def id=(id)
  @id = id.to_sym
end

#index=(value) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/masamune/schema/column.rb', line 86

def index=(value)
  @index ||= Set.new
  @index +=
  case value
  when true
    [id]
  when false
    []
  when String, Symbol
    [value.to_sym]
  when Array, Set
    value.map(&:to_sym)
  else
    raise ArgumentError
  end
end

#nameObject



68
69
70
71
72
73
74
# File 'lib/masamune/schema/column.rb', line 68

def name
  if reference && reference.columns.include?(id)
    [reference.label, reference.name, id].compact.join('_').to_sym
  else
    id
  end
end

#null_value?(value) ⇒ Boolean

Returns:

  • (Boolean)


330
331
332
333
334
335
336
337
338
339
340
# File 'lib/masamune/schema/column.rb', line 330

def null_value?(value)
  if type == :json || array_value?
    return true if value == 'NULL'
  end
  return false unless value
  if hive_encoding?
    value.to_s == '\N'
  else
    false
  end
end

#qualified_name(label = nil) ⇒ Object



137
138
139
# File 'lib/masamune/schema/column.rb', line 137

def qualified_name(label = nil)
  [label, (parent ? "#{parent.name}.#{name}" : name)].compact.join('_').to_sym
end

#reference_name(label = nil) ⇒ Object



141
142
143
# File 'lib/masamune/schema/column.rb', line 141

def reference_name(label = nil)
  qualified_name(label).to_s.tr('.', '_').to_sym
end

#references?(other) ⇒ Boolean

XXX hack to work around columns not being able to reference columns

Returns:

  • (Boolean)


425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
# File 'lib/masamune/schema/column.rb', line 425

def references?(other)
  return false unless other
  if reference && other.reference && reference.id == other.reference.id
    true
  elsif parent && other.parent && parent.id == other.parent.id
    self == other
  elsif parent && other.parent && other.parent.parent && parent.id == other.parent.parent.id
    self == other
  elsif reference && other.parent && reference.id == other.parent.id
    self == other
  elsif natural_key || other.natural_key
    self == other
  else
    false
  end
end

#required_value?Boolean

Returns:

  • (Boolean)


455
456
457
458
459
460
# File 'lib/masamune/schema/column.rb', line 455

def required_value?
  return false if reference && (reference.null || !reference.default.nil?)
  return false if null || !default.nil?
  return false unless strict
  true
end

#ruby_value(value, recursive = true) ⇒ Object



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/masamune/schema/column.rb', line 234

def ruby_value(value, recursive = true)
  value = nil if null_value?(value)
  return value if sql_function?(value)
  return ruby_array(value) if recursive && array_value?
  case type
  when :boolean
    case value
    when false, 0, '0', "'0'", /\Afalse\z/i
      false
    when true, 1, '1', "'1'", /\Atrue\z/i
      true
    end
  when :date
    case value
    when Date
      value
    when String
      Date.parse(value.to_s)
    when nil
      nil
    end
  when :timestamp
    case value
    when Time
      value
    when Date, DateTime
      value.to_time
    when String
      if value.blank?
        nil
      elsif value =~ /\A\d+\z/
        Time.at(value.to_i)
      else
        Time.parse(value)
      end
    when Integer
      Time.at(value)
    when nil
      nil
    end
  when :integer
    value.blank? ? nil : value.to_i
  when :yaml
    case value
    when Hash
      value
    when String
      YAML.safe_load(value, allowed_yaml_sub_type)
    when nil
      {}
    end
  when :json
    case value
    when Hash
      value
    when String
      JSON.parse(value).tap do |new_value|
        raise unless new_value.is_a?(Hash) || new_value.is_a?(Array)
      end
    when nil
      {}
    end
  when :string
    value.blank? ? nil : value.to_s
  else
    value
  end
rescue
  raise ArgumentError, "Could not coerce '#{value}' into :#{type} for column '#{name}'"
end

#sequence_idObject



451
452
453
# File 'lib/masamune/schema/column.rb', line 451

def sequence_id
  "#{reference_name}_seq" if type == :sequence
end

#sql_function?(value) ⇒ Boolean

Returns:

  • (Boolean)


350
351
352
# File 'lib/masamune/schema/column.rb', line 350

def sql_function?(value)
  value =~ /\(\)\Z/
end

#sql_type(for_surrogate_key = false) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/masamune/schema/column.rb', line 145

def sql_type(for_surrogate_key = false)
  elem =
  case type
  when :integer
    for_surrogate_key ? 'SERIAL' : 'INTEGER'
  when :money
    'MONEY'
  when :string
    'VARCHAR'
  when :uuid
    'UUID'
  when :date
    'DATE'
  when :timestamp
    'TIMESTAMP'
  when :boolean
    'BOOLEAN'
  when :sequence
    'INTEGER'
  when :enum
    "#{sub_type || id}_TYPE".upcase
  when :key_value
    if parent.type == :stage && !parent.inherit
      'JSON'
    else
      'HSTORE'
    end
  when :json, :yaml
    'JSON'
  end
  array_value? ? "#{elem}[]" : elem
end

#sql_value(value) ⇒ Object



191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/masamune/schema/column.rb', line 191

def sql_value(value)
  return value if sql_function?(value)
  return 'NULL' if value == :null
  case type
  when :boolean
    value ? 'TRUE' : 'FALSE'
  when :string
    "'#{value}'"
  when :enum
    "'#{value}'::#{sql_type}"
  else
    value
  end
end

#typecast?(other_type) ⇒ Boolean

Returns:

  • (Boolean)


406
407
408
409
410
411
412
413
414
415
416
417
418
# File 'lib/masamune/schema/column.rb', line 406

def typecast?(other_type)
  return true if type == other_type
  case [type, other_type]
  when i[key_value yaml]
    true
  when i[key_value json]
    true
  when i[yaml json]
    true
  else
    false
  end
end

#unique=(value) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/masamune/schema/column.rb', line 103

def unique=(value)
  @unique ||= Set.new
  @unique +=
  case value
  when true
    [id]
  when false
    []
  when String, Symbol
    [value.to_sym]
  when Array, Set
    value.map(&:to_sym)
  else
    raise ArgumentError
  end
end