ar-postgis 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Documentation.rdoc +292 -0
- data/History.rdoc +147 -0
- data/LICENSE.txt +29 -0
- data/README.rdoc +78 -0
- data/lib/active_record/connection_adapters/postgis_adapter.rb +38 -0
- data/lib/active_record/connection_adapters/postgis_adapter/rails4/create_connection.rb +29 -0
- data/lib/active_record/connection_adapters/postgis_adapter/rails4/databases.rake +17 -0
- data/lib/active_record/connection_adapters/postgis_adapter/rails4/main_adapter.rb +202 -0
- data/lib/active_record/connection_adapters/postgis_adapter/rails4/postgis_database_tasks.rb +204 -0
- data/lib/active_record/connection_adapters/postgis_adapter/rails4/spatial_column.rb +184 -0
- data/lib/active_record/connection_adapters/postgis_adapter/rails4/spatial_table_definition.rb +121 -0
- data/lib/active_record/connection_adapters/postgis_adapter/railtie.rb +3 -0
- data/lib/active_record/connection_adapters/postgis_adapter/shared/arel_tosql.rb +23 -0
- data/lib/active_record/connection_adapters/postgis_adapter/shared/common_adapter_methods.rb +46 -0
- data/lib/active_record/connection_adapters/postgis_adapter/shared/railtie.rb +13 -0
- data/lib/active_record/connection_adapters/postgis_adapter/shared/setup.rb +21 -0
- data/lib/active_record/connection_adapters/postgis_adapter/version.rb +7 -0
- data/lib/activerecord-postgis-adapter.rb +1 -0
- data/test/database.yml +5 -0
- data/test/tc_basic.rb +212 -0
- data/test/tc_ddl.rb +303 -0
- data/test/tc_nested_class.rb +48 -0
- data/test/tc_spatial_queries.rb +126 -0
- data/test/tc_tasks.rb +112 -0
- metadata +149 -0
@@ -0,0 +1,184 @@
|
|
1
|
+
module ActiveRecord # :nodoc:
|
2
|
+
|
3
|
+
module ConnectionAdapters # :nodoc:
|
4
|
+
|
5
|
+
module PostGISAdapter # :nodoc:
|
6
|
+
|
7
|
+
|
8
|
+
class SpatialColumn < ConnectionAdapters::PostgreSQLColumn # :nodoc:
|
9
|
+
|
10
|
+
|
11
|
+
def initialize(factory_settings_, table_name_, name_, default_, oid_type_, sql_type_=nil, null_=true, opts_=nil)
|
12
|
+
@factory_settings = factory_settings_
|
13
|
+
@table_name = table_name_
|
14
|
+
@geographic = sql_type_ =~ /geography/i ? true : false
|
15
|
+
if opts_
|
16
|
+
# This case comes from an entry in the geometry_columns table
|
17
|
+
@geometric_type = ::RGeo::ActiveRecord.geometric_type_from_name(opts_[:type]) ||
|
18
|
+
::RGeo::Feature::Geometry
|
19
|
+
@srid = opts_[:srid].to_i
|
20
|
+
@has_z = opts_[:has_z] ? true : false
|
21
|
+
@has_m = opts_[:has_m] ? true : false
|
22
|
+
elsif @geographic
|
23
|
+
# Geographic type information is embedded in the SQL type
|
24
|
+
@geometric_type = ::RGeo::Feature::Geometry
|
25
|
+
@srid = 4326
|
26
|
+
@has_z = @has_m = false
|
27
|
+
if sql_type_ =~ /geography\((.*)\)$/i
|
28
|
+
params_ = $1.split(',')
|
29
|
+
if params_.size >= 2
|
30
|
+
if params_.first =~ /([a-z]+[^zm])(z?)(m?)/i
|
31
|
+
@has_z = $2.length > 0
|
32
|
+
@has_m = $3.length > 0
|
33
|
+
@geometric_type = ::RGeo::ActiveRecord.geometric_type_from_name($1)
|
34
|
+
end
|
35
|
+
if params_.last =~ /(\d+)/
|
36
|
+
@srid = $1.to_i
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
elsif sql_type_ =~ /geography|geometry|point|linestring|polygon/i
|
41
|
+
# Just in case there is a geometry column with no geometry_columns entry.
|
42
|
+
@geometric_type = ::RGeo::Feature::Geometry
|
43
|
+
@srid = @has_z = @has_m = nil
|
44
|
+
else
|
45
|
+
# Non-spatial column
|
46
|
+
@geometric_type = @has_z = @has_m = @srid = nil
|
47
|
+
end
|
48
|
+
super(name_, default_, oid_type_, sql_type_, null_)
|
49
|
+
if spatial?
|
50
|
+
if @srid
|
51
|
+
@limit = {:srid => @srid, :type => @geometric_type.type_name.underscore}
|
52
|
+
@limit[:has_z] = true if @has_z
|
53
|
+
@limit[:has_m] = true if @has_m
|
54
|
+
@limit[:geographic] = true if @geographic
|
55
|
+
else
|
56
|
+
@limit = {:no_constraints => true}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
attr_reader :geographic
|
63
|
+
attr_reader :srid
|
64
|
+
attr_reader :geometric_type
|
65
|
+
attr_reader :has_z
|
66
|
+
attr_reader :has_m
|
67
|
+
|
68
|
+
alias_method :geographic?, :geographic
|
69
|
+
alias_method :has_z?, :has_z
|
70
|
+
alias_method :has_m?, :has_m
|
71
|
+
|
72
|
+
|
73
|
+
def spatial?
|
74
|
+
type == :spatial || type == :geography
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def has_spatial_constraints?
|
79
|
+
!@srid.nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
def klass
|
84
|
+
spatial? ? ::RGeo::Feature::Geometry : super
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
def type_cast(value_)
|
89
|
+
if spatial?
|
90
|
+
SpatialColumn.convert_to_geometry(value_, @factory_settings, @table_name, name,
|
91
|
+
@geographic, @srid, @has_z, @has_m)
|
92
|
+
else
|
93
|
+
super
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
|
101
|
+
def simplified_type(sql_type_)
|
102
|
+
sql_type_ =~ /geography|geometry|point|linestring|polygon/i ? :spatial : super
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
def self.convert_to_geometry(input_, factory_settings_, table_name_, column_, geographic_, srid_, has_z_, has_m_)
|
107
|
+
if srid_
|
108
|
+
constraints_ = {:geographic => geographic_, :has_z_coordinate => has_z_,
|
109
|
+
:has_m_coordinate => has_m_, :srid => srid_}
|
110
|
+
else
|
111
|
+
constraints_ = nil
|
112
|
+
end
|
113
|
+
if ::RGeo::Feature::Geometry === input_
|
114
|
+
factory_ = factory_settings_.get_column_factory(table_name_, column_, constraints_)
|
115
|
+
::RGeo::Feature.cast(input_, factory_) rescue nil
|
116
|
+
elsif input_.respond_to?(:to_str)
|
117
|
+
input_ = input_.to_str
|
118
|
+
if input_.length == 0
|
119
|
+
nil
|
120
|
+
else
|
121
|
+
factory_ = factory_settings_.get_column_factory(table_name_, column_, constraints_)
|
122
|
+
marker_ = input_[0,1]
|
123
|
+
if marker_ == "\x00" || marker_ == "\x01" || input_[0,4] =~ /[0-9a-fA-F]{4}/
|
124
|
+
::RGeo::WKRep::WKBParser.new(factory_, :support_ewkb => true).parse(input_) rescue nil
|
125
|
+
else
|
126
|
+
::RGeo::WKRep::WKTParser.new(factory_, :support_ewkt => true).parse(input_) rescue nil
|
127
|
+
end
|
128
|
+
end
|
129
|
+
else
|
130
|
+
nil
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
# Register spatial types with the postgres OID mechanism
|
139
|
+
# so we can recognize custom columns coming from the database.
|
140
|
+
|
141
|
+
class SpatialOID < PostgreSQLAdapter::OID::Type # :nodoc:
|
142
|
+
|
143
|
+
def initialize(factory_generator_)
|
144
|
+
@factory_generator = factory_generator_
|
145
|
+
end
|
146
|
+
|
147
|
+
def type_cast(value_)
|
148
|
+
return if value_.nil?
|
149
|
+
::RGeo::WKRep::WKBParser.new(@factory_generator, :support_ewkb => true).parse(value_) rescue nil
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
PostgreSQLAdapter::OID.register_type('geometry', SpatialOID.new(nil))
|
155
|
+
PostgreSQLAdapter::OID.register_type('geography', SpatialOID.new(::RGeo::Geographic.method(:spherical_factory)))
|
156
|
+
|
157
|
+
|
158
|
+
# This is a hack to ActiveRecord::ModelSchema. We have to "decorate" the decorate_columns
|
159
|
+
# method to apply class-specific customizations to spatial type casting.
|
160
|
+
|
161
|
+
module DecorateColumnsModification # :nodoc:
|
162
|
+
|
163
|
+
def decorate_columns(columns_hash_)
|
164
|
+
columns_hash_ = super(columns_hash_)
|
165
|
+
return unless columns_hash_
|
166
|
+
canonical_columns_ = self.columns_hash
|
167
|
+
columns_hash_.each do |name_, col_|
|
168
|
+
if col_.is_a?(SpatialOID) && (canonical_ = canonical_columns_[name_]) && canonical_.spatial?
|
169
|
+
columns_hash_[name_] = canonical_
|
170
|
+
end
|
171
|
+
end
|
172
|
+
columns_hash_
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
::ActiveRecord::Base.extend(DecorateColumnsModification)
|
178
|
+
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module ActiveRecord # :nodoc:
|
2
|
+
|
3
|
+
module ConnectionAdapters # :nodoc:
|
4
|
+
|
5
|
+
module PostGISAdapter # :nodoc:
|
6
|
+
|
7
|
+
|
8
|
+
class TableDefinition < ConnectionAdapters::PostgreSQLAdapter::TableDefinition # :nodoc:
|
9
|
+
|
10
|
+
def initialize(types_, name_, temporary_, options_, as_, base_)
|
11
|
+
@base = base_
|
12
|
+
@spatial_columns_hash = {}
|
13
|
+
super(types_, name_, temporary_, options_, as_)
|
14
|
+
end
|
15
|
+
|
16
|
+
def column(name_, type_, options_={})
|
17
|
+
if (info_ = @base.spatial_column_constructor(type_.to_sym))
|
18
|
+
type_ = options_[:type] || info_[:type] || type_
|
19
|
+
if type_.to_s == 'geometry' &&
|
20
|
+
(options_[:no_constraints] ||
|
21
|
+
options_[:limit].is_a?(::Hash) && options_[:limit][:no_constraints])
|
22
|
+
then
|
23
|
+
options_.delete(:limit)
|
24
|
+
else
|
25
|
+
options_[:type] = type_
|
26
|
+
type_ = :spatial
|
27
|
+
end
|
28
|
+
end
|
29
|
+
if type_ == :spatial
|
30
|
+
if (limit_ = options_.delete(:limit))
|
31
|
+
options_.merge!(limit_) if limit_.is_a?(::Hash)
|
32
|
+
end
|
33
|
+
if options_[:geographic]
|
34
|
+
type_ = :geography
|
35
|
+
spatial_type_ = (options_[:type] || 'geometry').to_s.upcase.gsub('_', '')
|
36
|
+
spatial_type_ << 'Z' if options_[:has_z]
|
37
|
+
spatial_type_ << 'M' if options_[:has_m]
|
38
|
+
options_[:limit] = "#{spatial_type_},#{options_[:srid] || 4326}"
|
39
|
+
end
|
40
|
+
name_ = name_.to_s
|
41
|
+
if primary_key_column_name == name_
|
42
|
+
raise ArgumentError, "you can't redefine the primary key column '#{name_}'. To define a custom primary key, pass { id: false } to create_table."
|
43
|
+
end
|
44
|
+
col_ = new_column_definition(name_, type_, options_)
|
45
|
+
col_.set_spatial_type(options_[:type])
|
46
|
+
col_.set_geographic(options_[:geographic])
|
47
|
+
col_.set_srid(options_[:srid])
|
48
|
+
col_.set_has_z(options_[:has_z])
|
49
|
+
col_.set_has_m(options_[:has_m])
|
50
|
+
(col_.geographic? ? @columns_hash : @spatial_columns_hash)[name_] = col_
|
51
|
+
else
|
52
|
+
super(name_, type_, options_)
|
53
|
+
end
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_column_definition(name_, type_)
|
58
|
+
if type_ == :spatial || type_ == :geography
|
59
|
+
PostGISAdapter::ColumnDefinition.new(name_, type_)
|
60
|
+
else
|
61
|
+
super
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def non_geographic_spatial_columns
|
66
|
+
@spatial_columns_hash.values
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
class ColumnDefinition < ConnectionAdapters::ColumnDefinition # :nodoc:
|
73
|
+
|
74
|
+
def spatial_type
|
75
|
+
@spatial_type
|
76
|
+
end
|
77
|
+
|
78
|
+
def geographic?
|
79
|
+
@geographic
|
80
|
+
end
|
81
|
+
|
82
|
+
def srid
|
83
|
+
@srid ? @srid.to_i : (geographic? ? 4326 : -1)
|
84
|
+
end
|
85
|
+
|
86
|
+
def has_z?
|
87
|
+
@has_z
|
88
|
+
end
|
89
|
+
|
90
|
+
def has_m?
|
91
|
+
@has_m
|
92
|
+
end
|
93
|
+
|
94
|
+
def set_geographic(value_)
|
95
|
+
@geographic = value_ ? true : false
|
96
|
+
end
|
97
|
+
|
98
|
+
def set_spatial_type(value_)
|
99
|
+
@spatial_type = value_.to_s
|
100
|
+
end
|
101
|
+
|
102
|
+
def set_srid(value_)
|
103
|
+
@srid = value_
|
104
|
+
end
|
105
|
+
|
106
|
+
def set_has_z(value_)
|
107
|
+
@has_z = value_ ? true : false
|
108
|
+
end
|
109
|
+
|
110
|
+
def set_has_m(value_)
|
111
|
+
@has_m = value_ ? true : false
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Arel # :nodoc:
|
2
|
+
module Visitors # :nodoc:
|
3
|
+
|
4
|
+
class PostGIS < PostgreSQL # :nodoc:
|
5
|
+
|
6
|
+
FUNC_MAP = {
|
7
|
+
'st_wkttosql' => 'ST_GeomFromEWKT',
|
8
|
+
}
|
9
|
+
|
10
|
+
include ::RGeo::ActiveRecord::SpatialToSql
|
11
|
+
|
12
|
+
def st_func(standard_name_)
|
13
|
+
FUNC_MAP[standard_name_.downcase] || standard_name_
|
14
|
+
end
|
15
|
+
|
16
|
+
alias_method :visit_in_spatial_context, :visit
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
VISITORS['postgis'] = ::Arel::Visitors::PostGIS
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ActiveRecord # :nodoc:
|
2
|
+
module ConnectionAdapters # :nodoc:
|
3
|
+
module PostGISAdapter # :nodoc:
|
4
|
+
SPATIAL_COLUMN_CONSTRUCTORS = ::RGeo::ActiveRecord::DEFAULT_SPATIAL_COLUMN_CONSTRUCTORS.merge(
|
5
|
+
:geography => {:type => 'geometry', :geographic => true}
|
6
|
+
)
|
7
|
+
|
8
|
+
module CommonAdapterMethods # :nodoc:
|
9
|
+
def set_rgeo_factory_settings(factory_settings_)
|
10
|
+
@rgeo_factory_settings = factory_settings_
|
11
|
+
end
|
12
|
+
|
13
|
+
def adapter_name
|
14
|
+
PostGISAdapter::ADAPTER_NAME
|
15
|
+
end
|
16
|
+
|
17
|
+
def spatial_column_constructor(name_)
|
18
|
+
PostGISAdapter::SPATIAL_COLUMN_CONSTRUCTORS[name_]
|
19
|
+
end
|
20
|
+
|
21
|
+
def postgis_lib_version
|
22
|
+
@postgis_lib_version ||= select_value("SELECT PostGIS_Lib_Version()")
|
23
|
+
end
|
24
|
+
|
25
|
+
# http://postgis.17.x6.nabble.com/Default-SRID-td5001115.html
|
26
|
+
def default_srid
|
27
|
+
0
|
28
|
+
end
|
29
|
+
|
30
|
+
def srs_database_columns
|
31
|
+
{:srtext_column => 'srtext', :proj4text_column => 'proj4text', :auth_name_column => 'auth_name', :auth_srid_column => 'auth_srid'}
|
32
|
+
end
|
33
|
+
|
34
|
+
def quote(value_, column_=nil)
|
35
|
+
if ::RGeo::Feature::Geometry.check_type(value_)
|
36
|
+
"'#{::RGeo::WKRep::WKBGenerator.new(:hex_format => true, :type_format => :ewkb, :emit_ewkb_srid => true).generate(value_)}'"
|
37
|
+
elsif value_.is_a?(::RGeo::Cartesian::BoundingBox)
|
38
|
+
"'#{value_.min_x},#{value_.min_y},#{value_.max_x},#{value_.max_y}'::box"
|
39
|
+
else
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
unless defined?(::ActiveRecord::ConnectionAdapters::PostGISAdapter::Railtie)
|
2
|
+
module ActiveRecord # :nodoc:
|
3
|
+
module ConnectionAdapters # :nodoc:
|
4
|
+
module PostGISAdapter # :nodoc:
|
5
|
+
class Railtie < ::Rails::Railtie # :nodoc:
|
6
|
+
rake_tasks do
|
7
|
+
load ::File.expand_path("../rails4/databases.rake", ::File.dirname(__FILE__))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActiveRecord # :nodoc:
|
2
|
+
|
3
|
+
module ConnectionAdapters # :nodoc:
|
4
|
+
|
5
|
+
module PostGISAdapter # :nodoc:
|
6
|
+
|
7
|
+
|
8
|
+
def self.initial_setup
|
9
|
+
gis_ignore_tables_ = ['geometry_columns', 'spatial_ref_sys', 'layer', 'topology']
|
10
|
+
ignore_tables_ = ::ActiveRecord::SchemaDumper.ignore_tables
|
11
|
+
gis_ignore_tables_.each do |table_|
|
12
|
+
ignore_tables_ << table_ unless ignore_tables_.include?(table_)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'active_record/connection_adapters/postgis_adapter.rb'
|
data/test/database.yml
ADDED
data/test/tc_basic.rb
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'rgeo/active_record/adapter_test_helper'
|
3
|
+
|
4
|
+
|
5
|
+
module RGeo
|
6
|
+
module ActiveRecord # :nodoc:
|
7
|
+
module PostGISAdapter # :nodoc:
|
8
|
+
module Tests # :nodoc:
|
9
|
+
|
10
|
+
class TestBasic < ::MiniTest::Test # :nodoc:
|
11
|
+
|
12
|
+
DATABASE_CONFIG_PATH = ::File.dirname(__FILE__)+'/database.yml'
|
13
|
+
OVERRIDE_DATABASE_CONFIG_PATH = ::File.dirname(__FILE__)+'/database_local.yml'
|
14
|
+
|
15
|
+
include AdapterTestHelper
|
16
|
+
|
17
|
+
define_test_methods do
|
18
|
+
|
19
|
+
|
20
|
+
def populate_ar_class(content_)
|
21
|
+
klass_ = create_ar_class
|
22
|
+
case content_
|
23
|
+
when :mercator_point
|
24
|
+
klass_.connection.create_table(:spatial_test) do |t_|
|
25
|
+
t_.column 'latlon', :point, :srid => 3785
|
26
|
+
end
|
27
|
+
when :latlon_point_geographic
|
28
|
+
klass_.connection.create_table(:spatial_test) do |t_|
|
29
|
+
t_.column 'latlon', :point, :srid => 4326, :geographic => true
|
30
|
+
end
|
31
|
+
when :no_constraints
|
32
|
+
klass_.connection.create_table(:spatial_test) do |t_|
|
33
|
+
t_.column 'geo', :geometry, :no_constraints => true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
klass_
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def test_version
|
41
|
+
refute_nil(::ActiveRecord::ConnectionAdapters::PostGISAdapter::VERSION)
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def test_postgis_available
|
46
|
+
connection_ = create_ar_class.connection
|
47
|
+
assert_equal('PostGIS', connection_.adapter_name)
|
48
|
+
refute_nil(connection_.postgis_lib_version)
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
def test_set_and_get_point
|
53
|
+
klass_ = populate_ar_class(:mercator_point)
|
54
|
+
obj_ = klass_.new
|
55
|
+
assert_nil(obj_.latlon)
|
56
|
+
obj_.latlon = @factory.point(1.0, 2.0)
|
57
|
+
assert_equal(@factory.point(1.0, 2.0), obj_.latlon)
|
58
|
+
assert_equal(3785, obj_.latlon.srid)
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def test_set_and_get_point_from_wkt
|
63
|
+
klass_ = populate_ar_class(:mercator_point)
|
64
|
+
obj_ = klass_.new
|
65
|
+
assert_nil(obj_.latlon)
|
66
|
+
obj_.latlon = 'POINT(1 2)'
|
67
|
+
assert_equal(@factory.point(1.0, 2.0), obj_.latlon)
|
68
|
+
assert_equal(3785, obj_.latlon.srid)
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
def test_save_and_load_point
|
73
|
+
klass_ = populate_ar_class(:mercator_point)
|
74
|
+
obj_ = klass_.new
|
75
|
+
obj_.latlon = @factory.point(1.0, 2.0)
|
76
|
+
obj_.save!
|
77
|
+
id_ = obj_.id
|
78
|
+
obj2_ = klass_.find(id_)
|
79
|
+
assert_equal(@factory.point(1.0, 2.0), obj2_.latlon)
|
80
|
+
assert_equal(3785, obj2_.latlon.srid)
|
81
|
+
assert_equal(true, ::RGeo::Geos.is_geos?(obj2_.latlon))
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def test_save_and_load_geographic_point
|
86
|
+
klass_ = populate_ar_class(:latlon_point_geographic)
|
87
|
+
obj_ = klass_.new
|
88
|
+
obj_.latlon = @factory.point(1.0, 2.0)
|
89
|
+
obj_.save!
|
90
|
+
id_ = obj_.id
|
91
|
+
obj2_ = klass_.find(id_)
|
92
|
+
assert_equal(@geographic_factory.point(1.0, 2.0), obj2_.latlon)
|
93
|
+
assert_equal(4326, obj2_.latlon.srid)
|
94
|
+
assert_equal(false, ::RGeo::Geos.is_geos?(obj2_.latlon))
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
def test_save_and_load_point_from_wkt
|
99
|
+
klass_ = populate_ar_class(:mercator_point)
|
100
|
+
obj_ = klass_.new
|
101
|
+
obj_.latlon = 'POINT(1 2)'
|
102
|
+
obj_.save!
|
103
|
+
id_ = obj_.id
|
104
|
+
obj2_ = klass_.find(id_)
|
105
|
+
assert_equal(@factory.point(1.0, 2.0), obj2_.latlon)
|
106
|
+
assert_equal(3785, obj2_.latlon.srid)
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
def test_set_point_bad_wkt
|
111
|
+
klass_ = populate_ar_class(:mercator_point)
|
112
|
+
obj_ = klass_.create(:latlon => 'POINT (x)')
|
113
|
+
assert_nil(obj_.latlon)
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
def test_set_point_wkt_wrong_type
|
118
|
+
klass_ = populate_ar_class(:mercator_point)
|
119
|
+
assert_raises(::ActiveRecord::StatementInvalid) do
|
120
|
+
klass_.create(:latlon => 'LINESTRING(1 2, 3 4, 5 6)')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
def test_custom_factory
|
126
|
+
klass_ = create_ar_class
|
127
|
+
klass_.connection.create_table(:spatial_test) do |t_|
|
128
|
+
t_.point(:latlon, :srid => 4326)
|
129
|
+
end
|
130
|
+
factory_ = ::RGeo::Geographic.simple_mercator_factory
|
131
|
+
klass_.class_eval do
|
132
|
+
set_rgeo_factory_for_column(:latlon, factory_)
|
133
|
+
end
|
134
|
+
rec_ = klass_.new
|
135
|
+
rec_.latlon = 'POINT(-122 47)'
|
136
|
+
assert_equal(factory_, rec_.latlon.factory)
|
137
|
+
rec_.save!
|
138
|
+
assert_equal(factory_, rec_.latlon.factory)
|
139
|
+
rec2_ = klass_.find(rec_.id)
|
140
|
+
assert_equal(factory_, rec2_.latlon.factory)
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
def test_readme_example
|
145
|
+
klass_ = create_ar_class
|
146
|
+
klass_.connection.create_table(:spatial_test) do |t_|
|
147
|
+
t_.column(:shape, :geometry)
|
148
|
+
t_.line_string(:path, :srid => 3785)
|
149
|
+
t_.point(:latlon, :geographic => true)
|
150
|
+
end
|
151
|
+
klass_.connection.change_table(:spatial_test) do |t_|
|
152
|
+
t_.index(:latlon, :spatial => true)
|
153
|
+
end
|
154
|
+
klass_.class_eval do
|
155
|
+
self.rgeo_factory_generator = ::RGeo::Geos.method(:factory)
|
156
|
+
set_rgeo_factory_for_column(:latlon, ::RGeo::Geographic.spherical_factory)
|
157
|
+
end
|
158
|
+
rec_ = klass_.new
|
159
|
+
rec_.latlon = 'POINT(-122 47)'
|
160
|
+
loc_ = rec_.latlon
|
161
|
+
assert_equal(47, loc_.latitude)
|
162
|
+
rec_.shape = loc_
|
163
|
+
assert_equal(true, ::RGeo::Geos.is_geos?(rec_.shape))
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
# no_constraints no longer supported in PostGIS 2.0
|
168
|
+
def _test_save_and_load_no_constraints
|
169
|
+
klass_ = populate_ar_class(:no_constraints)
|
170
|
+
factory1_ = ::RGeo::Cartesian.preferred_factory(:srid => 3785)
|
171
|
+
factory2_ = ::RGeo::Cartesian.preferred_factory(:srid => 2000)
|
172
|
+
obj_ = klass_.new
|
173
|
+
obj_.geo = factory1_.point(1.0, 2.0)
|
174
|
+
obj_.save!
|
175
|
+
id_ = obj_.id
|
176
|
+
obj2_ = klass_.find(id_)
|
177
|
+
assert_equal(factory1_.point(1.0, 2.0), obj2_.geo)
|
178
|
+
assert_equal(3785, obj2_.geo.srid)
|
179
|
+
obj2_.geo = factory2_.point(3.0, 4.0)
|
180
|
+
obj2_.save!
|
181
|
+
obj3_ = klass_.find(id_)
|
182
|
+
assert_equal(factory2_.point(3.0, 4.0), obj3_.geo)
|
183
|
+
assert_equal(2000, obj3_.geo.srid)
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
def test_point_to_json
|
188
|
+
klass_ = populate_ar_class(:mercator_point)
|
189
|
+
obj_ = klass_.new
|
190
|
+
assert_match(/"latlon":null/, obj_.to_json)
|
191
|
+
obj_.latlon = @factory.point(1.0, 2.0)
|
192
|
+
assert_match(/"latlon":"POINT\s\(1\.0\s2\.0\)"/, obj_.to_json)
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
def test_custom_column
|
197
|
+
klass_ = populate_ar_class(:mercator_point)
|
198
|
+
rec_ = klass_.new
|
199
|
+
rec_.latlon = 'POINT(0 0)'
|
200
|
+
rec_.save
|
201
|
+
refute_nil(klass_.select("CURRENT_TIMESTAMP as ts").first.ts)
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|