lib/chrono_model/adapter.rb in chrono_model-0.8.2 vs lib/chrono_model/adapter.rb in chrono_model-0.9.0

- old
+ new

@@ -1,8 +1,10 @@ require 'active_record' require 'active_record/connection_adapters/postgresql_adapter' +require 'multi_json' + module ChronoModel # This class implements all ActiveRecord::ConnectionAdapters::SchemaStatements # methods adding support for temporal extensions. It inherits from the Postgres # adapter for a clean override of its methods using super. @@ -283,23 +285,36 @@ def remove_column(table_name, *) return super unless is_chrono?(table_name) chrono_alter(table_name) { super } end - # Runs column_definitions, primary_key and indexes in the temporal schema, + # Runs column_definitions in the temporal schema, as the table there + # defined is the source for this information. + # + # The default search path is included however, since the table + # may reference types defined in other schemas, which result in their + # names becoming schema qualified, which will cause type resolutions to fail. + # + define_method(:column_definitions) do |table_name| + return super(table_name) unless is_chrono?(table_name) + on_schema(TEMPORAL_SCHEMA + ',' + self.schema_search_path, false) { super(table_name) } + end + + # Runs primary_key, indexes and default_sequence_name in the temporal schema, # as the table there defined is the source for this information. # # Moreover, the PostgreSQLAdapter +indexes+ method uses current_schema(), # thus this is the only (and cleanest) way to make injection work. # # Schema nesting is disabled on these calls, make sure to fetch metadata # from the first caller's selected schema and not from the current one. # - [:column_definitions, :primary_key, :indexes].each do |method| - define_method(method) do |table_name| - return super(table_name) unless is_chrono?(table_name) - _on_temporal_schema(false) { super(table_name) } + [:primary_key, :indexes, :default_sequence_name].each do |method| + define_method(method) do |*args| + table_name = args.first + return super(*args) unless is_chrono?(table_name) + _on_temporal_schema(false) { super(*args) } end end # Create spatial indexes for timestamp search. # @@ -452,10 +467,16 @@ else klasses.any? { |k| e.message =~ /#{k.name}/ } end end + def chrono_setup! + chrono_create_schemas + + chrono_upgrade_structure! + end + # HACK: Redefine tsrange parsing support, as it is broken currently. # # This self-made API is here because currently AR4 does not support # open-ended ranges. The reasons are poor support in Ruby: # @@ -466,36 +487,41 @@ # https://github.com/rails/rails/issues/13793 # https://github.com/rails/rails/issues/14010 # # so, for now, we are implementing our own. # - class TSRange < OID::Type - def extract_bounds(value) - from, to = value[1..-2].split(',') - { - from: (value[1] == ',' || from == '-infinity') ? nil : from[1..-2], - to: (value[-2] == ',' || to == 'infinity') ? nil : to[1..-2], - #exclude_start: (value[0] == '('), - #exclude_end: (value[-1] == ')') - } - end + class TSRange < ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Range + OID = 3908 - def type_cast(value) + def cast_value(value) + return if value == 'empty' + return value if value.is_a?(::Array) + extracted = extract_bounds(value) from = Conversions.string_to_utc_time extracted[:from] to = Conversions.string_to_utc_time extracted[:to ] [from, to] end + + def extract_bounds(value) + from, to = value[1..-2].split(',') + { + from: (value[1] == ',' || from == '-infinity') ? nil : from[1..-2], + to: (value[-2] == ',' || to == 'infinity') ? nil : to[1..-2], + } + end end - def chrono_setup! - chrono_create_schemas - chrono_setup_type_map + def initialize_type_map(type_map) + super.tap do + ar_type = type_map.fetch(TSRange::OID) + cm_type = TSRange.new(ar_type.subtype, ar_type.type) - chrono_upgrade_structure! + type_map.register_type TSRange::OID, cm_type + end end # Copy the indexes from the temporal table to the history table if the indexes # are not already created with the same name. # @@ -525,15 +551,9 @@ # def chrono_create_schemas [TEMPORAL_SCHEMA, HISTORY_SCHEMA].each do |schema| execute "CREATE SCHEMA #{schema}" unless schema_exists?(schema) end - end - - # Adds the above TSRange class to the PG Adapter OID::TYPE_MAP - # - def chrono_setup_type_map - OID::TYPE_MAP[3908] = TSRange.new end # Upgrades existing structure for each table, if required. # TODO: allow upgrades from pre-0.6 structure with box() and stuff. #