Module: OccamsRecord::TypeCaster
- Defined in:
- lib/occams-record/type_caster.rb
Constant Summary collapse
- CASTER =
case ActiveRecord::VERSION::MAJOR when 6, 7, 8 then :deserialize else raise "OccamsRecord::TypeCaster::CASTER does yet support this version of ActiveRecord" end
Class Method Summary collapse
-
.generate(column_names, column_types, model: nil) ⇒ Hash<Proc>
Returns a Hash containing type converters (a Proc) for each column.
Class Method Details
.generate(column_names, column_types, model: nil) ⇒ Hash<Proc>
Returns a Hash containing type converters (a Proc) for each column. The Proc’s accept a value and return a converted value, mapping enum values from the model if necessary.
NOTE Some columns may have no Proc (particularly if you’re using SQLite and running a raw SQL query).
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/occams-record/type_caster.rb', line 20 def self.generate(column_names, column_types, model: nil) column_names.each_with_object({}) { |col, memo| # # NOTE there's lots of variation between DB adapters and AR versions here. Some notes: # * Postgres AR < 6.1 `column_types` will contain entries for every column. # * Postgres AR >= 6.1 `column_types` only contains entries for "exotic" types. Columns with "common" types have already been converted by the PG adapter. # * SQLite `column_types` will always be empty. Some types will have already been convered by the SQLite adapter, but others will depend on # `model_column_types` for converstion. See test/raw_query_test.rb#test_common_types for examples. # * MySQL ? # type = column_types[col] || model&.attributes_builder&.types&.[](col) # # NOTE is also some variation in when enum values are mapped in different AR versions. # In >=5.0, <=7.0, ActiveRecord::Result objects *usually* contain the human-readable values. In 4.2 and # pre-release versions of 7.1, they instead have the RAW values (e.g. integers) which we must map ourselves. # enum = model&.defined_enums&.[](col) inv_enum = enum&.invert memo[col] = case type&.type when nil if enum ->(val) { enum.has_key?(val) ? val : inv_enum[val] } end when :datetime ->(val) { type.send(CASTER, val)&.in_time_zone } else if enum ->(val) { val = type.send(CASTER, val) enum.has_key?(val) ? val : inv_enum[val] } else ->(val) { type.send(CASTER, val) } end end } end |