Skip to content

Commit

Permalink
Merge pull request #125 from rgeo/spatial_column_info
Browse files Browse the repository at this point in the history
Do not query database for non-spatial tables
  • Loading branch information
teeparham committed Jun 11, 2014
2 parents 8077fbc + 4bde6b5 commit f352844
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 30 deletions.
1 change: 1 addition & 0 deletions activerecord-postgis-adapter.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ require './lib/active_record/connection_adapters/postgis_adapter/version.rb'
spec.add_dependency 'rgeo-activerecord', '~> 1.0.0'

spec.add_development_dependency 'rake', '~> 10.2'
spec.add_development_dependency 'mocha', '~> 1.0'
end
17 changes: 9 additions & 8 deletions lib/active_record/connection_adapters/postgis_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ module PostGISAdapter
require 'active_record/connection_adapters/postgresql_adapter'
require 'rgeo/active_record'

require 'active_record/connection_adapters/postgis_adapter/version.rb'
require 'active_record/connection_adapters/postgis_adapter/common_adapter_methods.rb'
require 'active_record/connection_adapters/postgis_adapter/main_adapter.rb'
require 'active_record/connection_adapters/postgis_adapter/spatial_table_definition.rb'
require 'active_record/connection_adapters/postgis_adapter/spatial_column.rb'
require 'active_record/connection_adapters/postgis_adapter/arel_tosql.rb'
require 'active_record/connection_adapters/postgis_adapter/setup.rb'
require 'active_record/connection_adapters/postgis_adapter/version'
require 'active_record/connection_adapters/postgis_adapter/common_adapter_methods'
require 'active_record/connection_adapters/postgis_adapter/main_adapter'
require 'active_record/connection_adapters/postgis_adapter/spatial_column_info'
require 'active_record/connection_adapters/postgis_adapter/spatial_table_definition'
require 'active_record/connection_adapters/postgis_adapter/spatial_column'
require 'active_record/connection_adapters/postgis_adapter/arel_tosql'
require 'active_record/connection_adapters/postgis_adapter/setup'
require 'active_record/connection_adapters/postgis_adapter/create_connection'
require 'active_record/connection_adapters/postgis_adapter/postgis_database_tasks.rb'
require 'active_record/connection_adapters/postgis_adapter/postgis_database_tasks'

::ActiveRecord::ConnectionAdapters::PostGISAdapter.initial_setup

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ def type_cast(value, column, array_member = false)
# FULL REPLACEMENT. RE-CHECK ON NEW VERSIONS
# https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
def columns(table_name, name = nil)
column_info = SpatialColumnInfo.new(self, quote_string(table_name.to_s))
# Limit, precision, and scale are all handled by the superclass.
spatial_info_ = spatial_column_info(table_name)
column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod|
oid = column_type_map.fetch(oid.to_i, fmod.to_i) { OID::Identity.new }
SpatialColumn.new(@rgeo_factory_settings,
Expand All @@ -42,7 +42,7 @@ def columns(table_name, name = nil)
oid,
type,
notnull == 'f',
type =~ /geometry/i ? spatial_info_[column_name] : nil)
column_info.get(column_name, type))
end
end

Expand Down Expand Up @@ -158,25 +158,7 @@ def add_index(table_name, column_name, options = {})
end

def spatial_column_info(table_name)
info = query("SELECT f_geometry_column,coord_dimension,srid,type FROM geometry_columns WHERE f_table_name='#{quote_string(table_name.to_s)}'")
result = {}
info.each do |row|
name = row[0]
type = row[3]
dimension = row[1].to_i
has_m = !!(type =~ /m$/i)
type.sub!(/m$/, '')
has_z = dimension > 3 || dimension == 3 && !has_m
result[name] = {
dimension: dimension,
has_m: has_m,
has_z: has_z,
name: name,
srid: row[2].to_i,
type: type,
}
end
result
SpatialColumnInfo.new(self, quote_string(table_name.to_s)).all
end

private
Expand Down Expand Up @@ -215,7 +197,6 @@ def set_dimensions(has_m, has_z)
dimensions += 1 if has_m
dimensions
end

end
end
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
module ActiveRecord # :nodoc:
module ConnectionAdapters # :nodoc:
module PostGISAdapter
# Do spatial sql queries for column info and memoize that info.
class SpatialColumnInfo
def initialize(adapter, table_name)
@adapter = adapter
@table_name = table_name
end

def all
info = @adapter.query("SELECT f_geometry_column,coord_dimension,srid,type FROM geometry_columns WHERE f_table_name='#{@table_name}'")
result = {}
info.each do |row|
name = row[0]
type = row[3]
dimension = row[1].to_i
has_m = !!(type =~ /m$/i)
type.sub!(/m$/, '')
has_z = dimension > 3 || dimension == 3 && !has_m
result[name] = {
dimension: dimension,
has_m: has_m,
has_z: has_z,
name: name,
srid: row[2].to_i,
type: type,
}
end
result
end

# will not query the database for non-spatial columns/tables
def get(column_name, type)
return nil unless type =~ /geometry/i
@spatial_column_info ||= all
@spatial_column_info[column_name]
end
end
end
end
end
24 changes: 24 additions & 0 deletions test/ddl_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,32 @@ def test_create_geometry_using_limit
assert_equal(0, klass.connection.select_value(geometry_column_count_query).to_i)
end

def test_caches_spatial_column_info
klass = create_ar_class
klass.connection.create_table(:spatial_test, force: true) do |t|
t.point 'latlon'
t.point 'other'
end
::ActiveRecord::ConnectionAdapters::PostGISAdapter::SpatialColumnInfo.any_instance.expects(:all).once.returns({})
klass.columns
klass.columns
end

def test_no_query_spatial_column_info
klass = create_ar_class
klass.connection.create_table(:spatial_test, force: true) do |t|
t.string 'name'
end
# `all` queries column info from the database - it should not be called when klass.columns is called
::ActiveRecord::ConnectionAdapters::PostGISAdapter::SpatialColumnInfo.any_instance.expects(:all).never
# first column is id, second is name
refute klass.columns[1].spatial?
assert_nil klass.columns[1].has_z
end
end

private

def geometry_column_count_query
"SELECT COUNT(*) FROM geometry_columns WHERE f_table_name='spatial_test'"
end
Expand Down

0 comments on commit f352844

Please sign in to comment.