From f14b07f57213b1978105a9eda15ef081d7ae7ca4 Mon Sep 17 00:00:00 2001 From: Dave Schweisguth Date: Thu, 29 Jun 2017 18:27:43 -0700 Subject: [PATCH] Upgrate Active Record dependency to 4.2. This commit reapplies fjl82 and agoln's commits from fjl82/activerecord-mysql2spatial-adapter to current master. Not all tests pass yet. --- activerecord-mysql2spatial-adapter.gemspec | 4 +- .../mysql2spatial_adapter.rb | 1 + .../mysql2spatial_adapter/main_adapter.rb | 15 +++- .../mysql2spatial_adapter/spatial_column.rb | 85 +------------------ lib/active_record/type/spatial.rb | 53 ++++++++++++ 5 files changed, 73 insertions(+), 85 deletions(-) create mode 100644 lib/active_record/type/spatial.rb diff --git a/activerecord-mysql2spatial-adapter.gemspec b/activerecord-mysql2spatial-adapter.gemspec index 0dda24b..b526e35 100644 --- a/activerecord-mysql2spatial-adapter.gemspec +++ b/activerecord-mysql2spatial-adapter.gemspec @@ -44,8 +44,8 @@ ['Version'] s_.extra_rdoc_files = ::Dir.glob("*.rdoc") s_.platform = ::Gem::Platform::RUBY - s_.add_dependency('activerecord', '>= 4.0', '< 4.2') - s_.add_dependency('rgeo-activerecord', '~> 1.3') + s_.add_dependency('activerecord', '~> 4.2.9') + s_.add_dependency('rgeo-activerecord', '~> 2.1.1') s_.add_dependency('mysql2', '>= 0.2.13', '< 0.4.0') s_.add_development_dependency('rake', '>= 0.9.2') s_.add_development_dependency('rdoc', '>= 3.12') diff --git a/lib/active_record/connection_adapters/mysql2spatial_adapter.rb b/lib/active_record/connection_adapters/mysql2spatial_adapter.rb index aa64fad..7489ea5 100644 --- a/lib/active_record/connection_adapters/mysql2spatial_adapter.rb +++ b/lib/active_record/connection_adapters/mysql2spatial_adapter.rb @@ -75,3 +75,4 @@ module Mysql2SpatialAdapter require 'active_record/connection_adapters/mysql2spatial_adapter/main_adapter.rb' require 'active_record/connection_adapters/mysql2spatial_adapter/spatial_column.rb' require 'active_record/connection_adapters/mysql2spatial_adapter/arel_tosql.rb' +require 'active_record/type/spatial.rb' diff --git a/lib/active_record/connection_adapters/mysql2spatial_adapter/main_adapter.rb b/lib/active_record/connection_adapters/mysql2spatial_adapter/main_adapter.rb index 192c85a..0b60b03 100644 --- a/lib/active_record/connection_adapters/mysql2spatial_adapter/main_adapter.rb +++ b/lib/active_record/connection_adapters/mysql2spatial_adapter/main_adapter.rb @@ -93,11 +93,11 @@ def add_index(table_name_, column_name_, options_={}) end def columns(table_name_, name_=nil) - result_ = execute("SHOW FIELDS FROM #{quote_table_name(table_name_)}", :skip_logging) + result_ = @connection.query "SHOW FULL FIELDS FROM #{quote_table_name(table_name_)}" columns_ = [] result_.each(symbolize_keys: true, as: :hash) do |field_| columns_ << SpatialColumn.new(@rgeo_factory_settings, table_name_.to_s, - field_[:Field], field_[:Default], field_[:Type], field_[:Null] == "YES") + field_[:Field], field_[:Default], lookup_cast_type(field_[:Type]), field_[:Type], field_[:Null] == "YES", field_[:Collation], field_[:Extra]) end columns_ end @@ -128,6 +128,17 @@ def indexes(table_name_, name_=nil) end indexes_ end + + protected + + def initialize_type_map(m) + super + register_class_with_limit m, %r(geometry)i, Type::Spatial + m.alias_type %r(point)i, 'geometry' + m.alias_type %r(linestring)i, 'geometry' + m.alias_type %r(polygon)i, 'geometry' + end + end end end diff --git a/lib/active_record/connection_adapters/mysql2spatial_adapter/spatial_column.rb b/lib/active_record/connection_adapters/mysql2spatial_adapter/spatial_column.rb index cab9cff..417bc3d 100644 --- a/lib/active_record/connection_adapters/mysql2spatial_adapter/spatial_column.rb +++ b/lib/active_record/connection_adapters/mysql2spatial_adapter/spatial_column.rb @@ -35,97 +35,20 @@ module ActiveRecord module ConnectionAdapters module Mysql2SpatialAdapter - - # ActiveRecord 3.2 uses ConnectionAdapters::Mysql2Adapter::Column - # whereas 3.0 and 3.1 use ConnectionAdapters::Mysql2Column - column_base_class_ = defined?(ConnectionAdapters::Mysql2Adapter::Column) ? - ConnectionAdapters::Mysql2Adapter::Column : ConnectionAdapters::Mysql2Column - - class SpatialColumn < column_base_class_ - + class SpatialColumn < ConnectionAdapters::Mysql2Adapter::Column FACTORY_SETTINGS_CACHE = {} - def initialize(factory_settings_, table_name_, name_, default_, sql_type_=nil, null_=true) - @factory_settings = factory_settings_ - @table_name = table_name_ - super(name_, default_,sql_type_, null_) - @geometric_type = ::RGeo::ActiveRecord.geometric_type_from_name(sql_type_) + def initialize(factory_settings_, table_name_, name_, default_, cast_type_ = nil, sql_type_ = nil, null_ = true, collation_ = nil, extra_ = "") + super(name_, default_, cast_type_, sql_type_, null_, collation_, false, extra_) if type == :spatial - @limit = { type: @geometric_type.type_name.underscore } + cast_type.set_geo_params(factory_settings_, table_name_, ::RGeo::ActiveRecord.geometric_type_from_name(sql_type_)) end FACTORY_SETTINGS_CACHE[factory_settings_.object_id] = factory_settings_ end - attr_reader :geometric_type - - def spatial? - type == :spatial - end - - def klass - type == :spatial ? ::RGeo::Feature::Geometry : super - end - - def type_cast(value_) - if type == :spatial - SpatialColumn.convert_to_geometry(value_, @factory_settings, @table_name, name) - else - super - end - end - - def type_cast_code(var_name_) - if type == :spatial - "::ActiveRecord::ConnectionAdapters::Mysql2SpatialAdapter::SpatialColumn.convert_to_geometry("+ - "#{var_name_}, ::ActiveRecord::ConnectionAdapters::Mysql2SpatialAdapter::SpatialColumn::"+ - "FACTORY_SETTINGS_CACHE[#{@factory_settings.object_id}], #{@table_name.inspect}, #{name.inspect})" - else - super - end - end - - private - - def simplified_type(sql_type_) - sql_type_ =~ /geometry|point|linestring|polygon/i ? :spatial : super - end - - - def self.convert_to_geometry(input_, factory_settings_, table_name_, column_) - case input_ - when ::RGeo::Feature::Geometry - factory_ = factory_settings_.get_column_factory(table_name_, column_, srid: input_.srid) - ::RGeo::Feature.cast(input_, factory_) rescue nil - when ::String - marker_ = input_[4,1] - if marker_ == "\x00" || marker_ == "\x01" - factory_ = factory_settings_.get_column_factory(table_name_, column_, - srid: input_[0, 4].unpack(marker_ == "\x01" ? 'V' : 'N').first) - ::RGeo::WKRep::WKBParser.new(factory_).parse(input_[4..-1]) rescue nil - elsif input_[0,10] =~ /[0-9a-fA-F]{8}0[01]/ - srid_ = input_[0,8].to_i(16) - if input[9,1] == '1' - srid_ = [srid_].pack('V').unpack('N').first - end - factory_ = factory_settings_.get_column_factory(table_name_, column_, srid: srid_) - ::RGeo::WKRep::WKBParser.new(factory_).parse(input_[8..-1]) rescue nil - else - factory_ = factory_settings_.get_column_factory(table_name_, column_) - ::RGeo::WKRep::WKTParser.new(factory_, support_ewkt: true).parse(input_) rescue nil - end - else - nil - end - end - - end - - end - end - end # :startdoc: diff --git a/lib/active_record/type/spatial.rb b/lib/active_record/type/spatial.rb new file mode 100644 index 0000000..f34df6d --- /dev/null +++ b/lib/active_record/type/spatial.rb @@ -0,0 +1,53 @@ +module ActiveRecord + module Type + class Spatial < Value # :nodoc: + def type + :spatial + end + + def spatial? + type == :spatial + end + + def klass + type == :spatial ? ::RGeo::Feature::Geometry : super + end + + def set_geo_params(factory_settings, table_name, geometric_type) + @factory_settings = factory_settings + @table_name = table_name + @geometric_type = geometric_type + end + + private + + def cast_value(value) + case value + when ::RGeo::Feature::Geometry + factory = @factory_settings.get_column_factory(@table_name, @column, :srid => value.srid) + ::RGeo::Feature.cast(value, factory) rescue nil + when ::String + marker = value[4,1] + if marker == "\x00" || marker == "\x01" + factory = @factory_settings.get_column_factory(@table_name, @column, + :srid => value[0,4].unpack(marker == "\x01" ? 'V' : 'N').first) + ::RGeo::WKRep::WKBParser.new(factory).parse(value[4..-1]) rescue nil + elsif value[0,10] =~ /[0-9a-fA-F]{8}0[01]/ + srid = value[0,8].to_i(16) + if value[9,1] == '1' + srid = [srid].pack('V').unpack('N').first + end + factory = @factory_settings.get_column_factory(@table_name, @column, :srid => srid) + ::RGeo::WKRep::WKBParser.new(factory).parse(value[8..-1]) rescue nil + else + factory = @factory_settings.get_column_factory(@table_name, @column) + ::RGeo::WKRep::WKTParser.new(factory, support_ewkt: true).parse(value) rescue nil + end + else + nil + end + end + + end + end +end