activerecord-postgis-adapter 0.3.5 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +12 -0
- data/README.rdoc +8 -4
- data/Version +1 -1
- data/lib/active_record/connection_adapters/postgis_adapter/main_adapter.rb +28 -1
- data/lib/active_record/connection_adapters/postgis_adapter/spatial_column.rb +13 -20
- data/test/tc_basic.rb +26 -10
- data/test/tc_spatial_queries.rb +13 -13
- metadata +5 -5
data/History.rdoc
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
=== 0.4.0 / 2011-08-15
|
2
|
+
|
3
|
+
* Various fixes for Rails 3.1 compatibility.
|
4
|
+
* Now requires rgeo-activerecord 0.4.0.
|
5
|
+
* INCOMPATIBLE CHANGE: simple queries (e.g. MyClass.where(:latlon => my_point)) use an objective rather than spatial equality test. Earlier versions transformed this form to use st_equals, but now if you need to test for spatial equality, you'll need to call st_equals explicitly. I'm still evaluating which direction we want to go with this in the future, but we may be stuck with the current behavior because the hack required to transform these queries to use spatial equality was egregious and broke in Rails 3.1 with no clear workaround.
|
6
|
+
|
7
|
+
=== 0.3.6 / 2011-06-21
|
8
|
+
|
9
|
+
* Require latest rgeo-activerecord to get some fixes.
|
10
|
+
* Note PostgreSQL 9 requirement in the README. (Reported by Samuel Cochran)
|
11
|
+
* Now doesn't throw exceptions if an RGeo cast fails when setting an attribute.
|
12
|
+
|
1
13
|
=== 0.3.5 / 2011-04-12
|
2
14
|
|
3
15
|
* The .gemspec was missing the databases.rake file. Fixed.
|
data/README.rdoc
CHANGED
@@ -89,7 +89,7 @@ Now you can interact with the data using the RGeo types:
|
|
89
89
|
|
90
90
|
=== Spatial Queries
|
91
91
|
|
92
|
-
You can create simple queries based on
|
92
|
+
You can create simple queries based on objective equality in the same way
|
93
93
|
you would on a scalar column:
|
94
94
|
|
95
95
|
rec = MySpatialTable.where(:latlon => RGeo::Geos.factory.point(-122, 47)).first
|
@@ -111,11 +111,13 @@ write more complex queries in SQL.
|
|
111
111
|
This adapter has the following requirements:
|
112
112
|
|
113
113
|
* Ruby 1.8.7 or later. Ruby 1.9.2 or later preferred.
|
114
|
+
* PostgreSQL 9.0 or later.
|
114
115
|
* PostGIS 1.5 or later.
|
115
|
-
* pg gem 0.
|
116
|
+
* pg gem 0.11 or later.
|
116
117
|
* \ActiveRecord 3.0.3 or later. Earlier versions will not work.
|
117
|
-
|
118
|
-
* rgeo
|
118
|
+
Appears to be compatible with Rails 3.1rc5.
|
119
|
+
* rgeo gem 0.3.2 or later.
|
120
|
+
* rgeo-activerecord gem 0.4.0 or later.
|
119
121
|
|
120
122
|
Install this adapter as a gem:
|
121
123
|
|
@@ -260,6 +262,8 @@ Contributions are welcome. Fork the project on Github.
|
|
260
262
|
|
261
263
|
Report bugs on Github issues at http://github.org/dazuma/activerecord-postgis-adapter/issues
|
262
264
|
|
265
|
+
Support available on the rgeo-users google group at http://groups.google.com/group/rgeo-users
|
266
|
+
|
263
267
|
Contact the author at dazuma at gmail dot com.
|
264
268
|
|
265
269
|
=== Acknowledgments
|
data/Version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
@@ -53,6 +53,11 @@ module ActiveRecord
|
|
53
53
|
@@native_database_types = nil
|
54
54
|
|
55
55
|
|
56
|
+
def set_rgeo_factory_settings(factory_settings_)
|
57
|
+
@rgeo_factory_settings = factory_settings_
|
58
|
+
end
|
59
|
+
|
60
|
+
|
56
61
|
def adapter_name
|
57
62
|
PostGISAdapter::ADAPTER_NAME
|
58
63
|
end
|
@@ -90,16 +95,30 @@ module ActiveRecord
|
|
90
95
|
end
|
91
96
|
|
92
97
|
|
98
|
+
def type_cast(value_, column_)
|
99
|
+
if ::RGeo::Feature::Geometry.check_type(value_)
|
100
|
+
::RGeo::WKRep::WKBGenerator.new(:hex_format => true, :type_format => :ewkb, :emit_ewkb_srid => true).generate(value_)
|
101
|
+
else
|
102
|
+
super
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
|
93
107
|
def columns(table_name_, name_=nil)
|
108
|
+
# FULL REPLACEMENT. RE-CHECK ON NEW VERSIONS.
|
109
|
+
# We needed to return a spatial column subclass.
|
94
110
|
table_name_ = table_name_.to_s
|
95
111
|
spatial_info_ = spatial_column_info(table_name_)
|
96
112
|
column_definitions(table_name_).collect do |name_, type_, default_, notnull_|
|
97
|
-
SpatialColumn.new(
|
113
|
+
SpatialColumn.new(@rgeo_factory_settings, table_name_.to_s, name_, default_, type_,
|
114
|
+
notnull_ == 'f', type_ =~ /geometry/i ? spatial_info_[name_] : nil)
|
98
115
|
end
|
99
116
|
end
|
100
117
|
|
101
118
|
|
102
119
|
def indexes(table_name_, name_=nil)
|
120
|
+
# FULL REPLACEMENT. RE-CHECK ON NEW VERSIONS.
|
121
|
+
# We needed to modify the catalog queries to pull the index type info.
|
103
122
|
|
104
123
|
# Remove postgis from schemas
|
105
124
|
schemas_ = schema_search_path.split(/,/)
|
@@ -143,6 +162,12 @@ module ActiveRecord
|
|
143
162
|
|
144
163
|
|
145
164
|
def create_table(table_name_, options_={})
|
165
|
+
# FULL REPLACEMENT. RE-CHECK ON NEW VERSIONS.
|
166
|
+
# Note: we have to do a full replacement for Rails 3.0 because
|
167
|
+
# there is no way to override the creation of the table
|
168
|
+
# definition object. In Rails 3.1, this has been factored out
|
169
|
+
# into the table_definition method, so we could rewrite this
|
170
|
+
# to call super if we're willing to go 3.1 only.
|
146
171
|
table_name_ = table_name_.to_s
|
147
172
|
table_definition_ = SpatialTableDefinition.new(self)
|
148
173
|
table_definition_.primary_key(options_[:primary_key] || ::ActiveRecord::Base.get_primary_key(table_name_.singularize)) unless options_[:id] == false
|
@@ -229,6 +254,8 @@ module ActiveRecord
|
|
229
254
|
|
230
255
|
|
231
256
|
def add_index(table_name_, column_name_, options_={})
|
257
|
+
# FULL REPLACEMENT. RE-CHECK ON NEW VERSIONS.
|
258
|
+
# We have to fully-replace because of the gist_clause.
|
232
259
|
table_name_ = table_name_.to_s
|
233
260
|
column_names_ = ::Array.wrap(column_name_)
|
234
261
|
index_name_ = index_name(table_name_, :column => column_names_)
|
@@ -46,7 +46,9 @@ module ActiveRecord
|
|
46
46
|
class SpatialColumn < ConnectionAdapters::PostgreSQLColumn
|
47
47
|
|
48
48
|
|
49
|
-
def initialize(name_, default_, sql_type_=nil, null_=true, opts_=nil)
|
49
|
+
def initialize(factory_settings_, table_name_, name_, default_, sql_type_=nil, null_=true, opts_=nil)
|
50
|
+
@factory_settings = factory_settings_
|
51
|
+
@table_name = table_name_
|
50
52
|
super(name_, default_, sql_type_, null_)
|
51
53
|
@geographic = sql_type_ =~ /geography/i ? true : false
|
52
54
|
if opts_
|
@@ -92,12 +94,6 @@ module ActiveRecord
|
|
92
94
|
@limit = {:no_constraints => true}
|
93
95
|
end
|
94
96
|
end
|
95
|
-
@ar_class = ::ActiveRecord::Base
|
96
|
-
end
|
97
|
-
|
98
|
-
|
99
|
-
def set_ar_class(val_)
|
100
|
-
@ar_class = val_
|
101
97
|
end
|
102
98
|
|
103
99
|
|
@@ -129,8 +125,8 @@ module ActiveRecord
|
|
129
125
|
|
130
126
|
def type_cast(value_)
|
131
127
|
if type == :spatial
|
132
|
-
SpatialColumn.convert_to_geometry(value_, @
|
133
|
-
@srid, @has_z, @has_m)
|
128
|
+
SpatialColumn.convert_to_geometry(value_, @factory_settings, @table_name, name,
|
129
|
+
@geographic, @srid, @has_z, @has_m)
|
134
130
|
else
|
135
131
|
super
|
136
132
|
end
|
@@ -140,8 +136,9 @@ module ActiveRecord
|
|
140
136
|
def type_cast_code(var_name_)
|
141
137
|
if type == :spatial
|
142
138
|
"::ActiveRecord::ConnectionAdapters::PostGISAdapter::SpatialColumn.convert_to_geometry("+
|
143
|
-
"#{var_name_}, self.class,
|
144
|
-
"#{
|
139
|
+
"#{var_name_}, self.class.rgeo_factory_settings, self.class.table_name, "+
|
140
|
+
"#{name.inspect}, #{@geographic ? 'true' : 'false'}, #{@srid.inspect}, "+
|
141
|
+
"#{@has_z ? 'true' : 'false'}, #{@has_m ? 'true' : 'false'})"
|
145
142
|
else
|
146
143
|
super
|
147
144
|
end
|
@@ -156,7 +153,7 @@ module ActiveRecord
|
|
156
153
|
end
|
157
154
|
|
158
155
|
|
159
|
-
def self.convert_to_geometry(input_,
|
156
|
+
def self.convert_to_geometry(input_, factory_settings_, table_name_, column_, geographic_, srid_, has_z_, has_m_)
|
160
157
|
if srid_
|
161
158
|
constraints_ = {:geographic => geographic_, :has_z_coordinate => has_z_,
|
162
159
|
:has_m_coordinate => has_m_, :srid => srid_}
|
@@ -165,18 +162,16 @@ module ActiveRecord
|
|
165
162
|
end
|
166
163
|
case input_
|
167
164
|
when ::RGeo::Feature::Geometry
|
168
|
-
factory_ =
|
169
|
-
::RGeo::Feature.cast(input_, factory_)
|
165
|
+
factory_ = factory_settings_.get_column_factory(table_name_, column_, constraints_)
|
166
|
+
::RGeo::Feature.cast(input_, factory_) rescue nil
|
170
167
|
when ::String
|
171
168
|
if input_.length == 0
|
172
169
|
nil
|
173
170
|
else
|
174
|
-
factory_ =
|
171
|
+
factory_ = factory_settings_.get_column_factory(table_name_, column_, constraints_)
|
175
172
|
marker_ = input_[0,1]
|
176
|
-
if marker_ == "\x00" || marker_ == "\x01"
|
173
|
+
if marker_ == "\x00" || marker_ == "\x01" || input_[0,4] =~ /[0-9a-fA-F]{4}/
|
177
174
|
::RGeo::WKRep::WKBParser.new(factory_, :support_ewkb => true).parse(input_) rescue nil
|
178
|
-
elsif input_[0,4] =~ /[0-9a-fA-F]{4}/
|
179
|
-
::RGeo::WKRep::WKBParser.new(factory_, :support_ewkb => true).parse_hex(input_) rescue nil
|
180
175
|
else
|
181
176
|
::RGeo::WKRep::WKTParser.new(factory_, :support_ewkt => true).parse(input_) rescue nil
|
182
177
|
end
|
@@ -192,10 +187,8 @@ module ActiveRecord
|
|
192
187
|
|
193
188
|
end
|
194
189
|
|
195
|
-
|
196
190
|
end
|
197
191
|
|
198
|
-
|
199
192
|
end
|
200
193
|
|
201
194
|
# :startdoc:
|
data/test/tc_basic.rb
CHANGED
@@ -53,9 +53,9 @@ module RGeo
|
|
53
53
|
def populate_ar_class(content_)
|
54
54
|
klass_ = create_ar_class
|
55
55
|
case content_
|
56
|
-
when :
|
56
|
+
when :mercator_point
|
57
57
|
klass_.connection.create_table(:spatial_test) do |t_|
|
58
|
-
t_.column 'latlon', :point, :srid =>
|
58
|
+
t_.column 'latlon', :point, :srid => 3785
|
59
59
|
end
|
60
60
|
when :latlon_point_geographic
|
61
61
|
klass_.connection.create_table(:spatial_test) do |t_|
|
@@ -83,34 +83,34 @@ module RGeo
|
|
83
83
|
|
84
84
|
|
85
85
|
def test_set_and_get_point
|
86
|
-
klass_ = populate_ar_class(:
|
86
|
+
klass_ = populate_ar_class(:mercator_point)
|
87
87
|
obj_ = klass_.new
|
88
88
|
assert_nil(obj_.latlon)
|
89
89
|
obj_.latlon = @factory.point(1, 2)
|
90
90
|
assert_equal(@factory.point(1, 2), obj_.latlon)
|
91
|
-
assert_equal(
|
91
|
+
assert_equal(3785, obj_.latlon.srid)
|
92
92
|
end
|
93
93
|
|
94
94
|
|
95
95
|
def test_set_and_get_point_from_wkt
|
96
|
-
klass_ = populate_ar_class(:
|
96
|
+
klass_ = populate_ar_class(:mercator_point)
|
97
97
|
obj_ = klass_.new
|
98
98
|
assert_nil(obj_.latlon)
|
99
99
|
obj_.latlon = 'POINT(1 2)'
|
100
100
|
assert_equal(@factory.point(1, 2), obj_.latlon)
|
101
|
-
assert_equal(
|
101
|
+
assert_equal(3785, obj_.latlon.srid)
|
102
102
|
end
|
103
103
|
|
104
104
|
|
105
105
|
def test_save_and_load_point
|
106
|
-
klass_ = populate_ar_class(:
|
106
|
+
klass_ = populate_ar_class(:mercator_point)
|
107
107
|
obj_ = klass_.new
|
108
108
|
obj_.latlon = @factory.point(1, 2)
|
109
109
|
obj_.save!
|
110
110
|
id_ = obj_.id
|
111
111
|
obj2_ = klass_.find(id_)
|
112
112
|
assert_equal(@factory.point(1, 2), obj2_.latlon)
|
113
|
-
assert_equal(
|
113
|
+
assert_equal(3785, obj2_.latlon.srid)
|
114
114
|
assert_equal(true, ::RGeo::Geos.is_geos?(obj2_.latlon))
|
115
115
|
end
|
116
116
|
|
@@ -129,14 +129,21 @@ module RGeo
|
|
129
129
|
|
130
130
|
|
131
131
|
def test_save_and_load_point_from_wkt
|
132
|
-
klass_ = populate_ar_class(:
|
132
|
+
klass_ = populate_ar_class(:mercator_point)
|
133
133
|
obj_ = klass_.new
|
134
134
|
obj_.latlon = 'POINT(1 2)'
|
135
135
|
obj_.save!
|
136
136
|
id_ = obj_.id
|
137
137
|
obj2_ = klass_.find(id_)
|
138
138
|
assert_equal(@factory.point(1, 2), obj2_.latlon)
|
139
|
-
assert_equal(
|
139
|
+
assert_equal(3785, obj2_.latlon.srid)
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
def test_set_point_bad_wkt
|
144
|
+
klass_ = populate_ar_class(:mercator_point)
|
145
|
+
obj_ = klass_.create(:latlon => 'POINT (x)')
|
146
|
+
assert_nil(obj_.latlon)
|
140
147
|
end
|
141
148
|
|
142
149
|
|
@@ -182,6 +189,15 @@ module RGeo
|
|
182
189
|
end
|
183
190
|
|
184
191
|
|
192
|
+
def test_point_to_json
|
193
|
+
klass_ = populate_ar_class(:mercator_point)
|
194
|
+
obj_ = klass_.new
|
195
|
+
assert_match(/"latlon":null/, obj_.to_json)
|
196
|
+
obj_.latlon = @factory.point(1, 2)
|
197
|
+
assert_match(/"latlon":"POINT\s\(1\.0\s2\.0\)"/, obj_.to_json)
|
198
|
+
end
|
199
|
+
|
200
|
+
|
185
201
|
end
|
186
202
|
|
187
203
|
end
|
data/test/tc_spatial_queries.rb
CHANGED
@@ -53,9 +53,9 @@ module RGeo
|
|
53
53
|
def populate_ar_class(content_)
|
54
54
|
klass_ = create_ar_class
|
55
55
|
case content_
|
56
|
-
when :
|
56
|
+
when :mercator_point
|
57
57
|
klass_.connection.create_table(:spatial_test) do |t_|
|
58
|
-
t_.column 'latlon', :point, :srid =>
|
58
|
+
t_.column 'latlon', :point, :srid => 3785
|
59
59
|
end
|
60
60
|
when :latlon_point_geographic
|
61
61
|
klass_.connection.create_table(:spatial_test) do |t_|
|
@@ -63,7 +63,7 @@ module RGeo
|
|
63
63
|
end
|
64
64
|
when :path_linestring
|
65
65
|
klass_.connection.create_table(:spatial_test) do |t_|
|
66
|
-
t_.column 'path', :line_string, :srid =>
|
66
|
+
t_.column 'path', :line_string, :srid => 3785
|
67
67
|
end
|
68
68
|
end
|
69
69
|
klass_
|
@@ -71,7 +71,7 @@ module RGeo
|
|
71
71
|
|
72
72
|
|
73
73
|
def test_query_point
|
74
|
-
klass_ = populate_ar_class(:
|
74
|
+
klass_ = populate_ar_class(:mercator_point)
|
75
75
|
obj_ = klass_.new
|
76
76
|
obj_.latlon = @factory.point(1, 2)
|
77
77
|
obj_.save!
|
@@ -84,14 +84,14 @@ module RGeo
|
|
84
84
|
|
85
85
|
|
86
86
|
def test_query_point_wkt
|
87
|
-
klass_ = populate_ar_class(:
|
87
|
+
klass_ = populate_ar_class(:mercator_point)
|
88
88
|
obj_ = klass_.new
|
89
89
|
obj_.latlon = @factory.point(1, 2)
|
90
90
|
obj_.save!
|
91
91
|
id_ = obj_.id
|
92
|
-
obj2_ = klass_.where(:latlon => 'SRID=
|
92
|
+
obj2_ = klass_.where(:latlon => 'SRID=3785;POINT(1 2)').first
|
93
93
|
assert_equal(id_, obj2_.id)
|
94
|
-
obj3_ = klass_.where(:latlon => 'SRID=
|
94
|
+
obj3_ = klass_.where(:latlon => 'SRID=3785;POINT(2 2)').first
|
95
95
|
assert_nil(obj3_)
|
96
96
|
end
|
97
97
|
|
@@ -100,27 +100,27 @@ module RGeo
|
|
100
100
|
|
101
101
|
|
102
102
|
def test_query_st_distance
|
103
|
-
klass_ = populate_ar_class(:
|
103
|
+
klass_ = populate_ar_class(:mercator_point)
|
104
104
|
obj_ = klass_.new
|
105
105
|
obj_.latlon = @factory.point(1, 2)
|
106
106
|
obj_.save!
|
107
107
|
id_ = obj_.id
|
108
|
-
obj2_ = klass_.where(klass_.arel_table[:latlon].st_distance('SRID=
|
108
|
+
obj2_ = klass_.where(klass_.arel_table[:latlon].st_distance('SRID=3785;POINT(2 3)').lt(2)).first
|
109
109
|
assert_equal(id_, obj2_.id)
|
110
|
-
obj3_ = klass_.where(klass_.arel_table[:latlon].st_distance('SRID=
|
110
|
+
obj3_ = klass_.where(klass_.arel_table[:latlon].st_distance('SRID=3785;POINT(2 3)').gt(2)).first
|
111
111
|
assert_nil(obj3_)
|
112
112
|
end
|
113
113
|
|
114
114
|
|
115
115
|
def test_query_st_distance_from_constant
|
116
|
-
klass_ = populate_ar_class(:
|
116
|
+
klass_ = populate_ar_class(:mercator_point)
|
117
117
|
obj_ = klass_.new
|
118
118
|
obj_.latlon = @factory.point(1, 2)
|
119
119
|
obj_.save!
|
120
120
|
id_ = obj_.id
|
121
|
-
obj2_ = klass_.where(::Arel.spatial('SRID=
|
121
|
+
obj2_ = klass_.where(::Arel.spatial('SRID=3785;POINT(2 3)').st_distance(klass_.arel_table[:latlon]).lt(2)).first
|
122
122
|
assert_equal(id_, obj2_.id)
|
123
|
-
obj3_ = klass_.where(::Arel.spatial('SRID=
|
123
|
+
obj3_ = klass_.where(::Arel.spatial('SRID=3785;POINT(2 3)').st_distance(klass_.arel_table[:latlon]).gt(2)).first
|
124
124
|
assert_nil(obj3_)
|
125
125
|
end
|
126
126
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: activerecord-postgis-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.4.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Daniel Azuma
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-08-15 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rgeo-activerecord
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ~>
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 0.
|
23
|
+
version: 0.4.0
|
24
24
|
type: :runtime
|
25
25
|
version_requirements: *id001
|
26
26
|
- !ruby/object:Gem::Dependency
|
@@ -31,7 +31,7 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 0.
|
34
|
+
version: 0.11.0
|
35
35
|
type: :runtime
|
36
36
|
version_requirements: *id002
|
37
37
|
description: This is an ActiveRecord connection adapter for PostGIS. It is based on the stock PostgreSQL adapter, but provides built-in support for the spatial extensions provided by PostGIS. It uses the RGeo library to represent spatial data in Ruby.
|
@@ -82,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
82
82
|
requirements: []
|
83
83
|
|
84
84
|
rubyforge_project: virtuoso
|
85
|
-
rubygems_version: 1.7
|
85
|
+
rubygems_version: 1.8.7
|
86
86
|
signing_key:
|
87
87
|
specification_version: 3
|
88
88
|
summary: An ActiveRecord adapter for PostGIS, based on RGeo.
|