bigrecord 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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