bigrecord 0.0.5

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 (104) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +44 -0
  3. data/Rakefile +17 -0
  4. data/VERSION +1 -0
  5. data/doc/bigrecord_specs.rdoc +36 -0
  6. data/doc/getting_started.rdoc +157 -0
  7. data/examples/bigrecord.yml +25 -0
  8. data/generators/bigrecord/bigrecord_generator.rb +17 -0
  9. data/generators/bigrecord/templates/bigrecord.rake +47 -0
  10. data/generators/bigrecord_migration/bigrecord_migration_generator.rb +13 -0
  11. data/generators/bigrecord_migration/templates/migration.rb +9 -0
  12. data/generators/bigrecord_model/bigrecord_model_generator.rb +28 -0
  13. data/generators/bigrecord_model/templates/migration.rb +13 -0
  14. data/generators/bigrecord_model/templates/model.rb +7 -0
  15. data/generators/bigrecord_model/templates/model_spec.rb +12 -0
  16. data/init.rb +9 -0
  17. data/install.rb +22 -0
  18. data/lib/big_record/abstract_base.rb +1088 -0
  19. data/lib/big_record/action_view_extensions.rb +266 -0
  20. data/lib/big_record/ar_associations/association_collection.rb +194 -0
  21. data/lib/big_record/ar_associations/association_proxy.rb +158 -0
  22. data/lib/big_record/ar_associations/belongs_to_association.rb +57 -0
  23. data/lib/big_record/ar_associations/belongs_to_many_association.rb +57 -0
  24. data/lib/big_record/ar_associations/has_and_belongs_to_many_association.rb +164 -0
  25. data/lib/big_record/ar_associations/has_many_association.rb +191 -0
  26. data/lib/big_record/ar_associations/has_one_association.rb +80 -0
  27. data/lib/big_record/ar_associations.rb +1608 -0
  28. data/lib/big_record/ar_reflection.rb +223 -0
  29. data/lib/big_record/attribute_methods.rb +75 -0
  30. data/lib/big_record/base.rb +618 -0
  31. data/lib/big_record/br_associations/association_collection.rb +194 -0
  32. data/lib/big_record/br_associations/association_proxy.rb +153 -0
  33. data/lib/big_record/br_associations/belongs_to_association.rb +52 -0
  34. data/lib/big_record/br_associations/belongs_to_many_association.rb +293 -0
  35. data/lib/big_record/br_associations/cached_item_proxy.rb +194 -0
  36. data/lib/big_record/br_associations/cached_item_proxy_factory.rb +62 -0
  37. data/lib/big_record/br_associations/has_and_belongs_to_many_association.rb +168 -0
  38. data/lib/big_record/br_associations/has_one_association.rb +80 -0
  39. data/lib/big_record/br_associations.rb +978 -0
  40. data/lib/big_record/br_reflection.rb +151 -0
  41. data/lib/big_record/callbacks.rb +367 -0
  42. data/lib/big_record/connection_adapters/abstract/connection_specification.rb +279 -0
  43. data/lib/big_record/connection_adapters/abstract/database_statements.rb +175 -0
  44. data/lib/big_record/connection_adapters/abstract/quoting.rb +58 -0
  45. data/lib/big_record/connection_adapters/abstract_adapter.rb +190 -0
  46. data/lib/big_record/connection_adapters/column.rb +491 -0
  47. data/lib/big_record/connection_adapters/hbase_adapter.rb +432 -0
  48. data/lib/big_record/connection_adapters/view.rb +27 -0
  49. data/lib/big_record/connection_adapters.rb +10 -0
  50. data/lib/big_record/deletion.rb +73 -0
  51. data/lib/big_record/dynamic_schema.rb +92 -0
  52. data/lib/big_record/embedded.rb +71 -0
  53. data/lib/big_record/embedded_associations/association_proxy.rb +148 -0
  54. data/lib/big_record/family_span_columns.rb +89 -0
  55. data/lib/big_record/fixtures.rb +1025 -0
  56. data/lib/big_record/migration.rb +380 -0
  57. data/lib/big_record/routing_ext.rb +65 -0
  58. data/lib/big_record/timestamp.rb +51 -0
  59. data/lib/big_record/validations.rb +830 -0
  60. data/lib/big_record.rb +125 -0
  61. data/lib/bigrecord.rb +1 -0
  62. data/rails/init.rb +9 -0
  63. data/spec/connections/bigrecord.yml +13 -0
  64. data/spec/connections/cassandra/connection.rb +2 -0
  65. data/spec/connections/hbase/connection.rb +2 -0
  66. data/spec/debug.log +281 -0
  67. data/spec/integration/br_associations_spec.rb +80 -0
  68. data/spec/lib/animal.rb +12 -0
  69. data/spec/lib/book.rb +10 -0
  70. data/spec/lib/broken_migrations/duplicate_name/20090706182535_add_animals_table.rb +14 -0
  71. data/spec/lib/broken_migrations/duplicate_name/20090706193019_add_animals_table.rb +9 -0
  72. data/spec/lib/broken_migrations/duplicate_version/20090706190623_add_books_table.rb +9 -0
  73. data/spec/lib/broken_migrations/duplicate_version/20090706190623_add_companies_table.rb +9 -0
  74. data/spec/lib/company.rb +14 -0
  75. data/spec/lib/embedded/web_link.rb +12 -0
  76. data/spec/lib/employee.rb +33 -0
  77. data/spec/lib/migrations/20090706182535_add_animals_table.rb +13 -0
  78. data/spec/lib/migrations/20090706190623_add_books_table.rb +15 -0
  79. data/spec/lib/migrations/20090706193019_add_companies_table.rb +14 -0
  80. data/spec/lib/migrations/20090706194512_add_employees_table.rb +13 -0
  81. data/spec/lib/migrations/20090706195741_add_zoos_table.rb +13 -0
  82. data/spec/lib/novel.rb +5 -0
  83. data/spec/lib/zoo.rb +17 -0
  84. data/spec/spec.opts +4 -0
  85. data/spec/spec_helper.rb +55 -0
  86. data/spec/unit/abstract_base_spec.rb +287 -0
  87. data/spec/unit/adapters/abstract_adapter_spec.rb +56 -0
  88. data/spec/unit/adapters/adapter_shared_spec.rb +51 -0
  89. data/spec/unit/adapters/hbase_adapter_spec.rb +15 -0
  90. data/spec/unit/ar_associations_spec.rb +8 -0
  91. data/spec/unit/base_spec.rb +6 -0
  92. data/spec/unit/br_associations_spec.rb +58 -0
  93. data/spec/unit/embedded_spec.rb +43 -0
  94. data/spec/unit/find_spec.rb +34 -0
  95. data/spec/unit/hash_helper_spec.rb +44 -0
  96. data/spec/unit/migration_spec.rb +144 -0
  97. data/spec/unit/model_spec.rb +315 -0
  98. data/spec/unit/validations_spec.rb +182 -0
  99. data/tasks/bigrecord_tasks.rake +47 -0
  100. data/tasks/data_store.rb +46 -0
  101. data/tasks/gem.rb +22 -0
  102. data/tasks/rdoc.rb +8 -0
  103. data/tasks/spec.rb +34 -0
  104. metadata +189 -0
@@ -0,0 +1,491 @@
1
+ require 'date'
2
+ require 'bigdecimal'
3
+ require 'bigdecimal/util'
4
+
5
+ module BigRecord
6
+ module ConnectionAdapters #:nodoc:
7
+ class Column
8
+ module Format
9
+ ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/
10
+ ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/
11
+ end
12
+
13
+ attr_reader :name, :type, :collection, :default, :alias
14
+ attr_accessor :primary
15
+
16
+ COLLECTION_SEPARATOR = "::"
17
+
18
+ def initialize(name, type, options={})
19
+ @type = type.to_sym
20
+ @collection = options[:collection]
21
+ @name = name.to_s
22
+ @alias = options[:alias] ? options[:alias].to_s : (self.class.extract_qualifier(@name) || (@name unless family?))
23
+
24
+ if options[:default]
25
+ @default = options[:default]
26
+ elsif @collection
27
+ @default = []
28
+ else
29
+ @default = (@type == :boolean) ? false : nil
30
+ end
31
+ # cache whether or not we'll need to dup the default columns to avoid clients to share
32
+ # the same reference to the default value
33
+ @must_dup_default = (!@default.nil? and (collection or (!number? and @type != :boolean)))
34
+
35
+ @primary = nil
36
+ end
37
+
38
+ # callback may be implemented by subclasses if value needs to be 'massaged' before instantiation.
39
+ def preinitialize(value)
40
+ # do something to a column value's attributes before it is instantiated.
41
+ end
42
+
43
+ def default
44
+ @must_dup_default ? @default.dup : @default
45
+ end
46
+
47
+ def text?
48
+ [:string, :text].include? type
49
+ end
50
+
51
+ def number?
52
+ [:float, :integer, :decimal].include? type
53
+ end
54
+
55
+ def primitive?
56
+ @primitive ||= ([:integer, :float, :decimal, :datetime, :date, :timestamp, :time, :text, :string, :binary, :boolean, :map, :object].include? type)
57
+ end
58
+
59
+ def family?
60
+ name =~ /:\Z/
61
+ end
62
+
63
+ def family
64
+ self.class.extract_family(self.name)
65
+ end
66
+
67
+ def qualifier
68
+ self.class.extract_qualifier(self.name)
69
+ end
70
+
71
+ def collection?
72
+ @collection
73
+ end
74
+
75
+ # Returns the Ruby class that corresponds to the abstract data type.
76
+ def klass
77
+ @klass ||=
78
+ case type
79
+ when :integer then Fixnum
80
+ when :float then Float
81
+ when :decimal then BigDecimal
82
+ when :datetime then Time
83
+ when :date then Date
84
+ when :timestamp then Time
85
+ when :time then Time
86
+ when :text, :string then String
87
+ when :binary then String
88
+ when :boolean then Object
89
+ when :map then Hash
90
+ when :object then Object
91
+ else type.to_s.constantize
92
+ end
93
+ end
94
+
95
+ # Casts value (which is a String) to an appropriate instance.
96
+ def type_cast(value)
97
+ # FIXME: this should be recursive but it doesn't work with type_cast_code()... why does
98
+ # ActiveRecord use type_cast_code ???
99
+ if collection?
100
+ return [] if value.nil?
101
+ case type
102
+ when :string then self.class.hash_to_string_collection(value)
103
+ when :text then self.class.hash_to_string_collection(value)
104
+ when :integer then self.class.hash_to_integer_collection(value)
105
+ when :float then self.class.hash_to_float_collection(value)
106
+ when :decimal then self.class.hash_to_decimal_collection(value)
107
+ when :datetime then self.class.hash_to_time_collection(value)
108
+ when :timestamp then self.class.hash_to_time_collection(value)
109
+ when :time then self.class.hash_to_dummy_time_collection(value)
110
+ when :date then self.class.hash_to_date_collection(value)
111
+ when :binary then self.class.hash_to_string_collection(value)
112
+ when :boolean then self.class.hash_to_boolean_collection(value)
113
+ when :map then value
114
+ when :object then value
115
+ else hash_to_embedded_collection(value)
116
+ end
117
+ else
118
+ casted_value =
119
+ case type
120
+ when :string then value
121
+ when :text then value
122
+ when :integer then value.to_i rescue value ? 1 : 0
123
+ when :float then value.to_f rescue value ? 1.0 : 0.0
124
+ when :decimal then self.class.value_to_decimal(value)
125
+ when :datetime then self.class.string_to_time(value)
126
+ when :timestamp then self.class.string_to_time(value)
127
+ when :time then self.class.string_to_dummy_time(value)
128
+ when :date then self.class.string_to_date(value)
129
+ when :binary then self.class.binary_to_string(value)
130
+ when :boolean then self.class.value_to_boolean(value)
131
+ when :map then value
132
+ when :object then value
133
+ else hash_to_embedded(value)
134
+ end
135
+ # Make sure that the returned value matches the current schema.
136
+ casted_value.is_a?(klass) ? casted_value : nil
137
+ end
138
+ end
139
+
140
+ def type_cast_code(var_name)
141
+ if collection?
142
+ case type
143
+ when :string then "#{self.class.name}.hash_to_string_collection(#{var_name})"
144
+ when :text then "#{self.class.name}.hash_to_string_collection(#{var_name})"
145
+ when :integer then "#{self.class.name}.hash_to_integer_collection(#{var_name})"
146
+ when :float then "#{self.class.name}.hash_to_float_collection(#{var_name})"
147
+ when :decimal then "#{self.class.name}.hash_to_decimal_collection(#{var_name})"
148
+ when :datetime then "#{self.class.name}.hash_to_time_collection(#{var_name})"
149
+ when :timestamp then "#{self.class.name}.hash_to_time_collection(#{var_name})"
150
+ when :time then "#{self.class.name}.hash_to_dummy_time_collection(#{var_name})"
151
+ when :date then "#{self.class.name}.hash_to_date_collection(#{var_name})"
152
+ when :binary then "#{self.class.name}.hash_to_string_collection(#{var_name})"
153
+ when :boolean then "#{self.class.name}.hash_to_boolean_collection(#{var_name})"
154
+ when :map then nil
155
+ when :object then nil
156
+ else nil
157
+ end
158
+ else
159
+ case type
160
+ when :string then nil
161
+ when :text then nil
162
+ when :integer then "(#{var_name}.to_i rescue #{var_name} ? 1 : 0)"
163
+ when :float then "#{var_name}.to_f"
164
+ when :decimal then "#{self.class.name}.value_to_decimal(#{var_name})"
165
+ when :datetime then "#{self.class.name}.string_to_time(#{var_name})"
166
+ when :timestamp then "#{self.class.name}.string_to_time(#{var_name})"
167
+ when :time then "#{self.class.name}.value_to_dummy_time(#{var_name})"
168
+ when :date then "#{self.class.name}.string_to_date(#{var_name})"
169
+ when :binary then "#{self.class.name}.binary_to_string(#{var_name})"
170
+ when :boolean then "#{self.class.name}.value_to_boolean(#{var_name})"
171
+ when :map then nil
172
+ when :object then nil
173
+ else nil
174
+ end
175
+ end
176
+ end
177
+
178
+ # Returns the human name of the column name.
179
+ #
180
+ # ===== Examples
181
+ # Column.new('sales_stage', ...).human_name #=> 'Sales stage'
182
+ def human_name
183
+ Base.human_attribute_name(@name)
184
+ end
185
+
186
+ def hash_to_embedded_collection(hash)
187
+ hash_collection = hash.is_a?(Hash) ? self.class.hash_to_collection(hash) : hash
188
+ hash_collection_to_embedded_collection(hash_collection)
189
+ end
190
+
191
+ def hash_collection_to_embedded_collection(hash_collection)
192
+ return hash_collection unless hash_collection.is_a?(Array)
193
+ hash_collection.each_with_index do |hash, i|
194
+ hash_collection[i] = hash_to_embedded(hash) if hash.is_a?(Hash)
195
+ end
196
+ hash_collection
197
+ end
198
+
199
+ def hash_to_embedded(value)
200
+ case value
201
+ when BigRecord::Embedded then value
202
+ when Hash then self.klass.instantiate(value)
203
+ end
204
+ end
205
+
206
+ class << self
207
+
208
+ # Extract the family from a column name
209
+ def extract_family(column_name)
210
+ return nil unless column_name
211
+ column_name =~ /\A(.*?:).*\Z/
212
+ $1
213
+ end
214
+
215
+ # Extract the qualifier from a column name
216
+ def extract_qualifier(column_name)
217
+ return nil unless column_name
218
+ column_name =~ /\A.*?:(.*)\Z/
219
+ $1
220
+ end
221
+
222
+ # Extract the collection from the hash, where the positions are the keys. Inspired
223
+ # from ActiveRecord::NestedAttributes.
224
+ #
225
+ # params = { 'member' => {
226
+ # 'name' => 'joe', 'posts_attributes' => {
227
+ # '1' => { 'title' => 'Kari, the awesome Ruby documentation browser!' },
228
+ # '2' => { 'title' => 'The egalitarian assumption of the modern citizen' },
229
+ # 'new_67890' => { 'title' => '' } # This one matches the :reject_if proc and will not be instantiated.
230
+ # }
231
+ # }}
232
+ def hash_to_collection(hash)
233
+ return hash unless hash.is_a?(Hash)
234
+
235
+ # Make sure any new records sorted by their id before they're build.
236
+ sorted_by_id = hash.sort_by { |id, _| id.is_a?(String) ? id.sub(/^new_/, '').to_i : id }
237
+
238
+ array = []
239
+ sorted_by_id.each do |id, record_attributes|
240
+ # remove blank records
241
+ next if blank_or_invalid_record?(record_attributes)
242
+
243
+ array << record_attributes
244
+ end
245
+ array
246
+ end
247
+
248
+ # Check if the given record is empty. It's recursive since it
249
+ # can be an Embedded
250
+ def blank_or_invalid_record?(record_attributes)
251
+ return true if record_attributes.blank? or !record_attributes.is_a?(Hash)
252
+ record_attributes.all? do |k, v|
253
+ v.is_a?(Hash) ? (v.empty? or blank_or_invalid_record?(v)) : v.blank?
254
+ end
255
+ end
256
+
257
+ def extract_callstack_for_multiparameter_attributes(pairs)
258
+ attributes = { }
259
+
260
+ for pair in pairs
261
+ multiparameter_name, value = pair
262
+ attribute_name = multiparameter_name.split("(").first
263
+ attributes[attribute_name] = [] unless attributes.include?(attribute_name)
264
+
265
+ unless value.empty?
266
+ attributes[attribute_name] <<
267
+ [ find_parameter_position(multiparameter_name), type_cast_attribute_value(multiparameter_name, value) ]
268
+ end
269
+ end
270
+
271
+ attributes.each { |name, values| attributes[name] = values.sort_by{ |v| v.first }.collect { |v| v.last } }
272
+ end
273
+
274
+ def parse_collection(value)
275
+ case value
276
+ when String then value.split(COLLECTION_SEPARATOR)
277
+ when Hash then value.values.first.scan(/\[(.*?)\]/).flatten
278
+ when NilClass then []
279
+ else value
280
+ end
281
+ end
282
+
283
+ # strings are a special case...
284
+ def hash_to_string_collection(value)
285
+ parse_collection(value).collect(&:to_s)
286
+ end
287
+
288
+ def hash_to_integer_collection(value)
289
+ parse_collection(value).collect(&:to_i)
290
+ end
291
+
292
+ def hash_to_float_collection(value)
293
+ parse_collection(value).collect(&:to_f)
294
+ end
295
+
296
+ def hash_to_decimal_collection(value)
297
+ parse_collection(value).collect{|v| value_to_decimal(v)}
298
+ end
299
+
300
+ def hash_to_date_collection(value)
301
+ parse_collection(value).collect{|v| string_to_date(v.to_s)}
302
+ end
303
+
304
+ def hash_to_time_collection(value)
305
+ parse_collection(value).collect{|v| string_to_time(v.to_s)}
306
+ end
307
+
308
+ def hash_to_dummy_time_collection(value)
309
+ parse_collection(value).collect{|v| string_to_dummy_time(v.to_s)}
310
+ end
311
+
312
+ # def hash_to_time_collection(hash)
313
+ # return []
314
+ # return hash unless hash.is_a?(Hash)
315
+ # hash_to_collection(hash).collect do |attributes|
316
+ # cleaned_attributes = {}
317
+ # debugger
318
+ # attributes.each do |k, v|
319
+ # k =~ /reflect_value(.*)/
320
+ # cleaned_attributes[$1] = v
321
+ # end
322
+ # string_to_time(cleaned_attributes)
323
+ # end
324
+ # end
325
+ #
326
+ # def hash_to_dummy_time_collection(hash)
327
+ # return []
328
+ # return hash unless hash.is_a?(Array)
329
+ # hash.split(COLLECTION_SEPARATOR).collect{|v|string_to_dummy_time(v)}
330
+ # end
331
+ #
332
+ # def hash_to_date_collection(hash)
333
+ # return []
334
+ # return hash unless hash.is_a?(Array)
335
+ # hash_to_collection(hash).collect do |attributes|
336
+ # debugger
337
+ # callstack = extract_callstack_for_multiparameter_attributes(attributes.to_a)
338
+ #
339
+ # end
340
+ # end
341
+
342
+ def hash_to_boolean_collection(value)
343
+ parse_collection(value).collect{|v| value_to_boolean(v)}
344
+ end
345
+
346
+ # Used to convert from Strings to BLOBs
347
+ def string_to_binary(value)
348
+ value
349
+ end
350
+
351
+ # Used to convert from BLOBs to Strings
352
+ def binary_to_string(value)
353
+ value
354
+ end
355
+
356
+ def string_to_date(string)
357
+ return string unless string.is_a?(String)
358
+ return nil if string.empty?
359
+
360
+ fast_string_to_date(string) || fallback_string_to_date(string)
361
+ end
362
+
363
+ def string_to_time(string)
364
+ return string unless string.is_a?(String)
365
+ return nil if string.empty?
366
+
367
+ fast_string_to_time(string) || fallback_string_to_time(string)
368
+ end
369
+
370
+ def string_to_dummy_time(string)
371
+ return string unless string.is_a?(String)
372
+ return nil if string.empty?
373
+
374
+ string_to_time "2000-01-01 #{string}"
375
+ end
376
+
377
+ # convert something to a boolean
378
+ def value_to_boolean(value)
379
+ if value == true || value == false
380
+ value
381
+ else
382
+ %w(true t 1).include?(value.to_s.downcase)
383
+ end
384
+ end
385
+
386
+ # convert something to a BigDecimal
387
+ def value_to_decimal(value)
388
+ if value.is_a?(BigDecimal)
389
+ value
390
+ elsif value.respond_to?(:to_d)
391
+ value.to_d
392
+ else
393
+ value.to_s.to_d
394
+ end
395
+ end
396
+
397
+ protected
398
+ # '0.123456' -> 123456
399
+ # '1.123456' -> 123456
400
+ def microseconds(time)
401
+ ((time[:sec_fraction].to_f % 1) * 1_000_000).to_i
402
+ end
403
+
404
+ def new_date(year, mon, mday)
405
+ if year && year != 0
406
+ Date.new(year, mon, mday) rescue nil
407
+ end
408
+ end
409
+
410
+ def new_time(year, mon, mday, hour, min, sec, microsec)
411
+ # Treat 0000-00-00 00:00:00 as nil.
412
+ return nil if year.nil? || year == 0
413
+
414
+ Time.send(Base.default_timezone, year, mon, mday, hour, min, sec, microsec)
415
+ # Over/underflow to DateTime
416
+ rescue ArgumentError, TypeError
417
+ zone_offset = Base.default_timezone == :local ? DateTime.local_offset : 0
418
+ DateTime.civil(year, mon, mday, hour, min, sec, zone_offset) rescue nil
419
+ end
420
+
421
+ def fast_string_to_date(string)
422
+ if string =~ Format::ISO_DATE
423
+ new_date $1.to_i, $2.to_i, $3.to_i
424
+ end
425
+ end
426
+
427
+ # Doesn't handle time zones.
428
+ def fast_string_to_time(string)
429
+ if string =~ Format::ISO_DATETIME
430
+ microsec = ($7.to_f * 1_000_000).to_i
431
+ new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec
432
+ end
433
+ end
434
+
435
+ def fallback_string_to_date(string)
436
+ new_date *ParseDate.parsedate(string)[0..2]
437
+ end
438
+
439
+ def fallback_string_to_time(string)
440
+ time_hash = Date._parse(string)
441
+ time_hash[:sec_fraction] = microseconds(time_hash)
442
+
443
+ new_time *time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction)
444
+ end
445
+ end
446
+
447
+ private
448
+ def extract_limit(sql_type)
449
+ $1.to_i if sql_type =~ /\((.*)\)/
450
+ end
451
+
452
+ def extract_precision(sql_type)
453
+ $2.to_i if sql_type =~ /^(numeric|decimal|number)\((\d+)(,\d+)?\)/i
454
+ end
455
+
456
+ def extract_scale(sql_type)
457
+ case sql_type
458
+ when /^(numeric|decimal|number)\((\d+)\)/i then 0
459
+ when /^(numeric|decimal|number)\((\d+)(,(\d+))\)/i then $4.to_i
460
+ end
461
+ end
462
+
463
+ def simplified_type(field_type)
464
+ case field_type
465
+ when /int/i
466
+ :integer
467
+ when /float|double/i
468
+ :float
469
+ when /decimal|numeric|number/i
470
+ extract_scale(field_type) == 0 ? :integer : :decimal
471
+ when /datetime/i
472
+ :datetime
473
+ when /timestamp/i
474
+ :timestamp
475
+ when /time/i
476
+ :time
477
+ when /date/i
478
+ :date
479
+ when /clob/i, /text/i
480
+ :text
481
+ when /blob/i, /binary/i
482
+ :binary
483
+ when /char/i, /string/i
484
+ :string
485
+ when /boolean/i
486
+ :boolean
487
+ end
488
+ end
489
+ end
490
+ end
491
+ end