activerecord-spatial 0.0.1
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 +15 -0
- data/.gitignore +16 -0
- data/Gemfile +21 -0
- data/Guardfile +17 -0
- data/MIT-LICENSE +23 -0
- data/README.rdoc +169 -0
- data/Rakefile +28 -0
- data/activerecord-spatial.gemspec +26 -0
- data/lib/activerecord-spatial.rb +32 -0
- data/lib/activerecord-spatial/active_record.rb +14 -0
- data/lib/activerecord-spatial/active_record/connection_adapters/postgresql/adapter_extensions.rb +36 -0
- data/lib/activerecord-spatial/active_record/connection_adapters/postgresql/postgis.rb +24 -0
- data/lib/activerecord-spatial/active_record/connection_adapters/postgresql/unknown_srid.rb +21 -0
- data/lib/activerecord-spatial/active_record/models/geography_column.rb +17 -0
- data/lib/activerecord-spatial/active_record/models/geometry_column.rb +17 -0
- data/lib/activerecord-spatial/active_record/models/spatial_column.rb +22 -0
- data/lib/activerecord-spatial/active_record/models/spatial_ref_sys.rb +20 -0
- data/lib/activerecord-spatial/associations.rb +292 -0
- data/lib/activerecord-spatial/spatial_columns.rb +345 -0
- data/lib/activerecord-spatial/spatial_function.rb +201 -0
- data/lib/activerecord-spatial/spatial_scope_constants.rb +114 -0
- data/lib/activerecord-spatial/spatial_scopes.rb +297 -0
- data/lib/activerecord-spatial/version.rb +5 -0
- data/lib/tasks/test.rake +45 -0
- data/test/accessors_geographies_tests.rb +149 -0
- data/test/accessors_geometries_tests.rb +151 -0
- data/test/adapter_tests.rb +44 -0
- data/test/associations_tests.rb +656 -0
- data/test/database.yml +17 -0
- data/test/fixtures/bars.yml +16 -0
- data/test/fixtures/blorts.yml +37 -0
- data/test/fixtures/foo3ds.yml +17 -0
- data/test/fixtures/foo_geographies.yml +16 -0
- data/test/fixtures/foos.yml +16 -0
- data/test/fixtures/zortables.yml +36 -0
- data/test/geography_column_tests.rb +40 -0
- data/test/geometry_column_tests.rb +40 -0
- data/test/models/bar.rb +17 -0
- data/test/models/blort.rb +12 -0
- data/test/models/foo.rb +17 -0
- data/test/models/foo3d.rb +17 -0
- data/test/models/foo_geography.rb +16 -0
- data/test/models/zortable.rb +17 -0
- data/test/spatial_scopes_geographies_tests.rb +106 -0
- data/test/spatial_scopes_tests.rb +444 -0
- data/test/test_helper.rb +272 -0
- metadata +138 -0
@@ -0,0 +1,444 @@
|
|
1
|
+
|
2
|
+
$: << File.dirname(__FILE__)
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class SpatialScopesTests < ActiveRecordSpatialTestCase
|
6
|
+
def self.before_suite
|
7
|
+
load_models(:foo, :foo3d)
|
8
|
+
end
|
9
|
+
|
10
|
+
def ids_tester(method, args, ids = [], klass = Foo)
|
11
|
+
geoms = klass.send(method, *Array.wrap(args)).all
|
12
|
+
assert_equal(ids.sort, geoms.collect(&:id).sort)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_contains
|
16
|
+
ids_tester(:st_contains, 'POINT(3 3)', [ 3 ])
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_containsproperly
|
20
|
+
ids_tester(:st_containsproperly, 'LINESTRING(-4 -4, 4 4)', [ 3 ])
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_covers
|
24
|
+
ids_tester(:st_covers, 'LINESTRING(-4 -4, 4 4)', [ 3 ])
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_coveredby
|
28
|
+
ids_tester(:st_coveredby, 'POLYGON((-6 -6, -6 6, 6 6, 6 -6, -6 -6))', [ 1, 3 ])
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_crosses
|
32
|
+
ids_tester(:st_crosses, 'LINESTRING(-6 -6, 4 4)', [ 3 ])
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_disjoint
|
36
|
+
ids_tester(:st_disjoint, 'POINT(100 100)', [ 1, 2, 3 ])
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_equal
|
40
|
+
ids_tester(:st_equals, 'POLYGON((-5 -5, -5 5, 5 5, 5 -5, -5 -5))', [ 3 ])
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_intersects
|
44
|
+
ids_tester(:st_intersects, 'LINESTRING(-5 -5, 10 10)', [ 1, 2, 3 ])
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_orderingequals
|
48
|
+
ids_tester(:st_orderingequals, 'POLYGON((-5 -5, -5 5, 5 5, 5 -5, -5 -5))', [ 3 ])
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_overlaps
|
52
|
+
ids_tester(:st_overlaps, 'POLYGON((-6 -6, -5 0, 0 0, 0 -5, -6 -6))', [ 3 ])
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_touches
|
56
|
+
ids_tester(:st_touches, 'POLYGON((-5 -5, -5 -10, -10 -10, -10 -5, -5 -5))', [ 3 ])
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_within
|
60
|
+
ids_tester(:st_within, 'POLYGON((-5 -5, 5 10, 20 20, 10 5, -5 -5))', [ 1, 2 ])
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_dwithin
|
64
|
+
ids_tester(:st_dwithin, [ 'POINT(5 5)', 10 ], [ 1, 2, 3 ])
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_dfullywithin
|
68
|
+
ids_tester(:st_dfullywithin, [ 'POINT(5 5)', 10 ], [ 1, 2 ])
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_geometry_type
|
72
|
+
ids_tester(:st_geometry_type, 'ST_Point', [ 1, 2 ])
|
73
|
+
ids_tester(:st_geometry_type, [ 'ST_Point', 'ST_Polygon' ], [ 1, 2, 3 ])
|
74
|
+
ids_tester(:st_geometry_type, [ 'ST_MultiLineString' ], [])
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_allow_null
|
78
|
+
begin
|
79
|
+
foo = Foo.create(:name => 'four')
|
80
|
+
ids_tester(:st_contains, [ 'POINT(3 3)', { :allow_null => true } ], [ 3, foo.id ])
|
81
|
+
ensure
|
82
|
+
Foo.find_by_name('four').destroy
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_nil_relationship
|
87
|
+
assert_equal([ 1, 2, 3 ], Foo.st_within(nil).all.collect(&:id).sort)
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_with_column
|
91
|
+
assert_equal([1, 2, 3], Foo.st_disjoint('POINT(100 100)', :column => :the_other_geom).all.collect(&:id).sort)
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_with_srid_switching
|
95
|
+
assert_equal([1, 2, 3], Foo.st_disjoint('SRID=4326; POINT(100 100)').all.collect(&:id).sort)
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_with_srid_default
|
99
|
+
assert_equal([1, 2, 3], Foo.st_disjoint('SRID=default; POINT(100 100)').all.collect(&:id).sort)
|
100
|
+
assert_equal([3], Foo.st_contains('SRID=default; POINT(-3 -3)').all.collect(&:id).sort)
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_with_srid_transform
|
104
|
+
assert_equal([1, 2, 3], Foo.st_disjoint('SRID=4269; POINT(100 100)', :column => :the_other_geom).all.collect(&:id).sort)
|
105
|
+
assert_equal([3], Foo.st_contains('SRID=4269; POINT(7 7)', :column => :the_other_geom).all.collect(&:id).sort)
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_order_by_st_distance
|
109
|
+
assert_equal([3, 1, 2], Foo.order_by_st_distance('POINT(1 1)').all.collect(&:id))
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_order_by_st_distance_desc
|
113
|
+
assert_equal([2, 1, 3], Foo.order_by_st_distance('POINT(1 1)', :desc => true).all.collect(&:id))
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_order_by_st_distance_sphere
|
117
|
+
assert_equal([3, 1, 2], Foo.order_by_st_distance_sphere('POINT(1 1)').all.collect(&:id))
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_order_by_st_distance_sphere_desc
|
121
|
+
assert_equal([2, 1, 3], Foo.order_by_st_distance_sphere('POINT(1 1)', :desc => true).all.collect(&:id))
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_order_by_st_max_distance
|
125
|
+
assert_equal([1, 3, 2], Foo.order_by_st_maxdistance('POINT(1 1)').all.collect(&:id))
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_order_by_st_max_distance_desc
|
129
|
+
assert_equal([2, 3, 1], Foo.order_by_st_maxdistance('POINT(1 1)', :desc => true).all.collect(&:id))
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_order_by_st_area
|
133
|
+
assert_equal([1, 2, 3], Foo.order_by_st_area.order('id').all.collect(&:id))
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_order_by_st_area_desc
|
137
|
+
assert_equal([3, 1, 2], Foo.order_by_st_area(:desc => true).order('id').all.collect(&:id))
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_order_by_st_ndims
|
141
|
+
assert_equal([1, 2, 3], Foo.order_by_st_ndims.order('id').all.collect(&:id))
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_order_by_st_ndims_desc
|
145
|
+
assert_equal([1, 2, 3], Foo.order_by_st_ndims(:desc => true).order('id').all.collect(&:id))
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_order_by_st_npoints
|
149
|
+
assert_equal([1, 2, 3], Foo.order_by_st_npoints.order('id').all.collect(&:id))
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_order_by_st_npoints_desc
|
153
|
+
assert_equal([3, 1, 2], Foo.order_by_st_npoints(:desc => true).order('id').all.collect(&:id))
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_order_by_st_nrings
|
157
|
+
assert_equal([1, 2, 3], Foo.order_by_st_nrings.order('id').all.collect(&:id))
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_order_by_st_nrings_desc
|
161
|
+
assert_equal([3, 1, 2], Foo.order_by_st_nrings(:desc => true).order('id').all.collect(&:id))
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_order_by_st_numgeometries
|
165
|
+
assert_equal([1, 2, 3], Foo.order_by_st_numgeometries.order('id').all.collect(&:id))
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_order_by_st_numgeometries_desc
|
169
|
+
assert_equal([1, 2, 3], Foo.order_by_st_numgeometries(:desc => true).order('id').all.collect(&:id))
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_order_by_st_numinteriorring
|
173
|
+
assert_equal([3, 1, 2], Foo.order_by_st_numinteriorring.order('id').all.collect(&:id))
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_order_by_st_numinteriorring_desc
|
177
|
+
assert_equal([1, 2, 3], Foo.order_by_st_numinteriorring(:desc => true).order('id').all.collect(&:id))
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_order_by_st_numinteriorrings
|
181
|
+
assert_equal([3, 1, 2], Foo.order_by_st_numinteriorrings.order('id').all.collect(&:id))
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_order_by_st_numinteriorrings_desc
|
185
|
+
assert_equal([1, 2, 3], Foo.order_by_st_numinteriorrings(:desc => true).order('id').all.collect(&:id))
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_order_by_st_numpoints
|
189
|
+
assert_equal([1, 2, 3], Foo.order_by_st_numpoints.order('id').all.collect(&:id))
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_order_by_st_numpoints_desc
|
193
|
+
assert_equal([1, 2, 3], Foo.order_by_st_numpoints(:desc => true).order('id').all.collect(&:id))
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_order_by_st_length3d
|
197
|
+
assert_equal([1, 2, 3], Foo.order_by_st_length3d.order('id').all.collect(&:id))
|
198
|
+
end
|
199
|
+
|
200
|
+
def test_order_by_st_length3d_desc
|
201
|
+
assert_equal([1, 2, 3], Foo.order_by_st_length3d(:desc => true).order('id').all.collect(&:id))
|
202
|
+
end
|
203
|
+
|
204
|
+
def test_order_by_st_length
|
205
|
+
assert_equal([1, 2, 3], Foo.order_by_st_length.order('id').all.collect(&:id))
|
206
|
+
end
|
207
|
+
|
208
|
+
def test_order_by_st_length_desc
|
209
|
+
assert_equal([1, 2, 3], Foo.order_by_st_length(:desc => true).order('id').all.collect(&:id))
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_order_by_st_length2d
|
213
|
+
assert_equal([1, 2, 3], Foo.order_by_st_length2d.order('id').all.collect(&:id))
|
214
|
+
end
|
215
|
+
|
216
|
+
def test_order_by_st_length2d_desc
|
217
|
+
assert_equal([1, 2, 3], Foo.order_by_st_length2d(:desc => true).order('id').all.collect(&:id))
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_order_by_st_length3d_spheroid
|
221
|
+
assert_equal([1, 2, 3], Foo.order_by_st_length3d_spheroid('SPHEROID["WGS 84", 6378137, 298.257223563]').order('id').all.collect(&:id))
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_order_by_st_length3d_spheroid_desc
|
225
|
+
expected = if ActiveRecordSpatial::POSTGIS[:lib] >= '2.0'
|
226
|
+
[3, 1, 2]
|
227
|
+
else
|
228
|
+
[1, 2, 3]
|
229
|
+
end
|
230
|
+
|
231
|
+
assert_equal(expected, Foo.order_by_st_length3d_spheroid('SPHEROID["WGS 84", 6378137, 298.257223563]', :desc => true).order('id').all.collect(&:id))
|
232
|
+
end
|
233
|
+
|
234
|
+
def test_order_by_st_length2d_spheroid
|
235
|
+
assert_equal([1, 2, 3], Foo.order_by_st_length2d_spheroid('SPHEROID["WGS 84", 6378137, 298.257223563]').order('id').all.collect(&:id))
|
236
|
+
end
|
237
|
+
|
238
|
+
def test_order_by_st_length2d_spheroid_desc
|
239
|
+
assert_equal([3, 1, 2], Foo.order_by_st_length2d_spheroid('SPHEROID["WGS 84", 6378137, 298.257223563]', :desc => true).order('id').all.collect(&:id))
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_order_by_st_length_spheroid
|
243
|
+
assert_equal([1, 2, 3], Foo.order_by_st_length_spheroid('SPHEROID["WGS 84", 6378137, 298.257223563]').order('id').all.collect(&:id))
|
244
|
+
end
|
245
|
+
|
246
|
+
def test_order_by_st_length_spheroid_desc
|
247
|
+
expected = if ActiveRecordSpatial::POSTGIS[:lib] >= '2.0'
|
248
|
+
[3, 1, 2]
|
249
|
+
else
|
250
|
+
[1, 2, 3]
|
251
|
+
end
|
252
|
+
|
253
|
+
assert_equal(expected, Foo.order_by_st_length_spheroid('SPHEROID["WGS 84", 6378137, 298.257223563]', :desc => true).order('id').all.collect(&:id))
|
254
|
+
end
|
255
|
+
|
256
|
+
def test_order_by_st_perimeter
|
257
|
+
assert_equal([1, 2, 3], Foo.order_by_st_perimeter.order('id').all.collect(&:id))
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_order_by_st_perimeter_desc
|
261
|
+
assert_equal([3, 1, 2], Foo.order_by_st_perimeter(:desc => true).order('id').all.collect(&:id))
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_order_by_st_perimeter2d
|
265
|
+
assert_equal([1, 2, 3], Foo.order_by_st_perimeter2d.order('id').all.collect(&:id))
|
266
|
+
end
|
267
|
+
|
268
|
+
def test_order_by_st_perimeter2d_desc
|
269
|
+
assert_equal([3, 1, 2], Foo.order_by_st_perimeter2d(:desc => true).order('id').all.collect(&:id))
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_order_by_st_perimeter3d
|
273
|
+
assert_equal([1, 2, 3], Foo.order_by_st_perimeter3d.order('id').all.collect(&:id))
|
274
|
+
end
|
275
|
+
|
276
|
+
def test_order_by_st_perimeter3d_desc
|
277
|
+
assert_equal([3, 1, 2], Foo.order_by_st_perimeter3d(:desc => true).order('id').all.collect(&:id))
|
278
|
+
end
|
279
|
+
|
280
|
+
def test_order_by_st_hausdorffdistance
|
281
|
+
assert_equal([1, 3, 2], Foo.order_by_st_hausdorffdistance('POINT(1 1)').all.collect(&:id))
|
282
|
+
end
|
283
|
+
|
284
|
+
def test_order_by_st_hausdorffdistance_desc
|
285
|
+
assert_equal([2, 3, 1], Foo.order_by_st_hausdorffdistance('POINT(1 1)', :desc => true).all.collect(&:id))
|
286
|
+
end
|
287
|
+
|
288
|
+
def test_order_by_st_hausdorffdistance_with_densify_frac
|
289
|
+
assert_equal([1, 3, 2], Foo.order_by_st_hausdorffdistance('POINT(1 1)', 0.314).all.collect(&:id))
|
290
|
+
end
|
291
|
+
|
292
|
+
def test_order_by_st_distance_spheroid
|
293
|
+
assert_equal([2, 3, 1], Foo.order_by_st_distance_spheroid('POINT(10 10)', 'SPHEROID["WGS 84", 6378137, 298.257223563]').order('id').all.collect(&:id))
|
294
|
+
end
|
295
|
+
|
296
|
+
def test_order_by_st_distance_spheroid_desc
|
297
|
+
assert_equal([1, 3, 2], Foo.order_by_st_distance_spheroid('POINT(10 10)', 'SPHEROID["WGS 84", 6378137, 298.257223563]', :desc => true).order('id').all.collect(&:id))
|
298
|
+
end
|
299
|
+
|
300
|
+
def test_order_by_st_area_with_desc_symbol
|
301
|
+
assert_equal([3, 1, 2], Foo.order_by_st_area(:desc).order('id').all.collect(&:id))
|
302
|
+
end
|
303
|
+
|
304
|
+
def test_3dintersects
|
305
|
+
skip('ST_3dintersects is unavailable') unless Foo3d.respond_to?(:st_3dintersects)
|
306
|
+
|
307
|
+
ids_tester(:st_3dintersects, 'LINESTRING(-5 -5 -5, 10 10 10)', [ 1, 3 ], Foo3d)
|
308
|
+
end
|
309
|
+
|
310
|
+
def test_3ddistance
|
311
|
+
skip('ST_3ddistance is unavailable') unless Foo3d.respond_to?(:order_by_st_3ddistance)
|
312
|
+
|
313
|
+
assert_equal([3, 2, 1], Foo3d.order_by_st_3ddistance('POINT(10 10)').order('id').all.collect(&:id))
|
314
|
+
end
|
315
|
+
|
316
|
+
def test_3dmaxdistance
|
317
|
+
skip('ST_3dmaxdistance is unavailable') unless Foo3d.respond_to?(:order_by_st_3dmaxdistance)
|
318
|
+
|
319
|
+
assert_equal([2, 1, 3], Foo3d.order_by_st_3dmaxdistance('POINT(10 10)').order('id').all.collect(&:id))
|
320
|
+
end
|
321
|
+
|
322
|
+
def test_3ddwithin
|
323
|
+
skip('ST_3ddwithin is unavailable') unless Foo3d.respond_to?(:st_3ddwithin)
|
324
|
+
|
325
|
+
ids_tester(:st_3ddwithin, [ 'LINESTRING(-5 -5 -5, 10 10 10)', 10 ], [ 1, 2, 3 ], Foo3d)
|
326
|
+
end
|
327
|
+
|
328
|
+
def test_3ddfullywithin
|
329
|
+
skip('ST_3ddfullywithin is unavilable') unless Foo3d.respond_to?(:st_3ddfullywithin)
|
330
|
+
|
331
|
+
ids_tester(:st_3ddfullywithin, [ 'LINESTRING(-10 -10 -10, 10 10 10)', 100 ], [ 1, 2, 3 ], Foo3d)
|
332
|
+
end
|
333
|
+
|
334
|
+
def test_order_by_with_column_wrapper
|
335
|
+
values = nil
|
336
|
+
|
337
|
+
assert_sql(/ST_envelope\("foos"."the_geom"\)/) do
|
338
|
+
values = Foo.
|
339
|
+
order_by_st_perimeter(
|
340
|
+
:desc => true,
|
341
|
+
:column => {
|
342
|
+
:wrapper => :envelope
|
343
|
+
}
|
344
|
+
).order('id').all.collect(&:id)
|
345
|
+
end
|
346
|
+
|
347
|
+
assert_equal([3, 1, 2], values)
|
348
|
+
end
|
349
|
+
|
350
|
+
def test_order_by_with_column_wrapper_and_an_option
|
351
|
+
values = nil
|
352
|
+
|
353
|
+
assert_sql(/ST_geometryn\("foos"."the_geom", 1\)/) do
|
354
|
+
values = Foo.
|
355
|
+
order_by_st_perimeter(
|
356
|
+
:desc => true,
|
357
|
+
:column => {
|
358
|
+
:wrapper => {
|
359
|
+
:geometryn => 1
|
360
|
+
}
|
361
|
+
}
|
362
|
+
).order('id').all.collect(&:id)
|
363
|
+
end
|
364
|
+
|
365
|
+
assert_equal([3, 1, 2], values)
|
366
|
+
end
|
367
|
+
|
368
|
+
def test_order_by_with_column_wrapper_and_options
|
369
|
+
values = nil
|
370
|
+
|
371
|
+
assert_sql(/ST_snap\("foos"."the_geom", 'POINT \(0 0\)', 1.0\)/) do
|
372
|
+
values = Foo.
|
373
|
+
order_by_st_perimeter(
|
374
|
+
:desc => true,
|
375
|
+
:column => {
|
376
|
+
:wrapper => {
|
377
|
+
:snap => [
|
378
|
+
'POINT (0 0)',
|
379
|
+
1.0
|
380
|
+
]
|
381
|
+
}
|
382
|
+
}
|
383
|
+
).order('id').all.collect(&:id)
|
384
|
+
end
|
385
|
+
|
386
|
+
assert_equal([3, 1, 2], values)
|
387
|
+
end
|
388
|
+
|
389
|
+
def test_relationship_with_column_wrapper
|
390
|
+
values = nil
|
391
|
+
|
392
|
+
assert_sql(/ST_centroid\("foos"."the_geom"\)/) do
|
393
|
+
values = Foo.
|
394
|
+
st_within(
|
395
|
+
'POLYGON((-5 -5, 5 10, 20 20, 10 5, -5 -5))',
|
396
|
+
:column => {
|
397
|
+
:wrapper => :centroid
|
398
|
+
}
|
399
|
+
).order('id').all.collect(&:id)
|
400
|
+
end
|
401
|
+
|
402
|
+
assert_equal([1, 2, 3], values)
|
403
|
+
end
|
404
|
+
|
405
|
+
def test_relationship_with_column_wrapper_and_option
|
406
|
+
values = nil
|
407
|
+
|
408
|
+
assert_sql(/ST_geometryn\("foos"."the_geom", 1\)/) do
|
409
|
+
values = Foo.
|
410
|
+
st_within(
|
411
|
+
'POLYGON((-5 -5, 5 10, 20 20, 10 5, -5 -5))',
|
412
|
+
:column => {
|
413
|
+
:wrapper => {
|
414
|
+
:geometryn => 1
|
415
|
+
}
|
416
|
+
}
|
417
|
+
).order('id').all.collect(&:id)
|
418
|
+
end
|
419
|
+
|
420
|
+
assert_equal([1, 2], values)
|
421
|
+
end
|
422
|
+
|
423
|
+
def test_relationship_with_column_wrapper_and_options
|
424
|
+
values = nil
|
425
|
+
|
426
|
+
assert_sql(/ST_snap\("foos"."the_geom", 'POINT \(0 0\)', 1.0\)/) do
|
427
|
+
values = Foo.
|
428
|
+
st_within(
|
429
|
+
'POLYGON((-5 -5, 5 10, 20 20, 10 5, -5 -5))',
|
430
|
+
:column => {
|
431
|
+
:wrapper => {
|
432
|
+
:snap => [
|
433
|
+
'POINT (0 0)',
|
434
|
+
1.0
|
435
|
+
]
|
436
|
+
}
|
437
|
+
}
|
438
|
+
).order('id').all.collect(&:id)
|
439
|
+
end
|
440
|
+
|
441
|
+
assert_equal([1, 2], values)
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,272 @@
|
|
1
|
+
|
2
|
+
require 'simplecov'
|
3
|
+
|
4
|
+
SimpleCov.command_name('Unit Tests')
|
5
|
+
SimpleCov.start do
|
6
|
+
add_filter '/test/'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'minitest/autorun'
|
11
|
+
require 'minitest/reporters'
|
12
|
+
require 'active_support'
|
13
|
+
require 'active_support/core_ext/module/aliasing'
|
14
|
+
require 'active_support/dependencies'
|
15
|
+
require 'active_record'
|
16
|
+
require 'active_record/fixtures'
|
17
|
+
require 'logger'
|
18
|
+
|
19
|
+
require File.join(File.dirname(__FILE__), %w{ .. lib activerecord-spatial })
|
20
|
+
|
21
|
+
POSTGIS_PATHS = [
|
22
|
+
ENV['POSTGIS_PATH'],
|
23
|
+
'/opt/local/share/postgresql*/contrib/postgis-*',
|
24
|
+
'/usr/share/postgresql*/contrib/postgis-*',
|
25
|
+
'/usr/pgsql-*/share/contrib/postgis-*',
|
26
|
+
].compact
|
27
|
+
|
28
|
+
puts "Testing against ActiveRecord #{Gem.loaded_specs['activerecord'].version.to_s}"
|
29
|
+
puts "Ruby version #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} - #{RbConfig::CONFIG['RUBY_INSTALL_NAME']}"
|
30
|
+
puts "Geos library version #{Geos::VERSION}" if defined?(Geos::VERSION)
|
31
|
+
puts "GEOS version #{Geos::GEOS_VERSION}"
|
32
|
+
puts "GEOS extensions version #{Geos::GEOS_EXTENSIONS_VERSION}"
|
33
|
+
if defined?(Geos::FFIGeos)
|
34
|
+
puts "Using #{Geos::FFIGeos.geos_library_paths.join(', ')}"
|
35
|
+
end
|
36
|
+
|
37
|
+
ActiveRecord::Base.logger = Logger.new("debug.log") if ENV['ENABLE_LOGGER']
|
38
|
+
ActiveRecord::Base.configurations = {
|
39
|
+
'arunit' => {}
|
40
|
+
}
|
41
|
+
|
42
|
+
%w{
|
43
|
+
database.yml
|
44
|
+
local_database.yml
|
45
|
+
}.each do |file|
|
46
|
+
file = File.join('test', file)
|
47
|
+
|
48
|
+
next unless File.exists?(file)
|
49
|
+
|
50
|
+
configuration = YAML.load(File.read(file))
|
51
|
+
|
52
|
+
if configuration['arunit']
|
53
|
+
ActiveRecord::Base.configurations['arunit'].merge!(configuration['arunit'])
|
54
|
+
end
|
55
|
+
|
56
|
+
if defined?(JRUBY_VERSION) && configuration['jdbc']
|
57
|
+
ActiveRecord::Base.configurations['arunit'].merge!(configuration['jdbc'])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
ActiveRecord::Base.establish_connection 'arunit'
|
62
|
+
ARBC = ActiveRecord::Base.connection
|
63
|
+
|
64
|
+
if postgresql_version = ARBC.select_rows('SELECT version()').first.first
|
65
|
+
puts "PostgreSQL info from version(): #{postgresql_version}"
|
66
|
+
end
|
67
|
+
|
68
|
+
puts "Checking for PostGIS install"
|
69
|
+
2.times do
|
70
|
+
begin
|
71
|
+
if postgis_version = ActiveRecordSpatial::POSTGIS[:lib]
|
72
|
+
puts "PostGIS info from postgis_full_version(): #{postgis_version}"
|
73
|
+
break
|
74
|
+
end
|
75
|
+
rescue ActiveRecord::StatementInvalid
|
76
|
+
puts "Trying to install PostGIS. If this doesn't work, you'll have to do this manually!"
|
77
|
+
|
78
|
+
plpgsql = ARBC.select_rows(%{SELECT count(*) FROM pg_language WHERE lanname = 'plpgsql'}).first.first.to_i
|
79
|
+
if plpgsql == 0
|
80
|
+
ARBC.execute(%{CREATE LANGUAGE plpgsql})
|
81
|
+
end
|
82
|
+
|
83
|
+
%w{
|
84
|
+
postgis.sql
|
85
|
+
spatial_ref_sys.sql
|
86
|
+
}.each do |file|
|
87
|
+
if !(found = Dir.glob(POSTGIS_PATHS).collect { |path|
|
88
|
+
File.join(path, file)
|
89
|
+
}.first)
|
90
|
+
puts "ERROR: Couldn't find #{file}. Try setting the POSTGIS_PATH to give us a hint!"
|
91
|
+
exit
|
92
|
+
else
|
93
|
+
ARBC.execute(File.read(found))
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class ActiveRecordSpatialTestCase < ActiveRecord::TestCase
|
100
|
+
BASE_PATH = Pathname.new(File.dirname(__FILE__))
|
101
|
+
|
102
|
+
include ActiveRecord::TestFixtures
|
103
|
+
self.fixture_path = BASE_PATH.join('fixtures')
|
104
|
+
|
105
|
+
REGEXP_WKB_HEX = /[A-Fa-f0-9\s]+/
|
106
|
+
|
107
|
+
POINT_WKT = 'POINT(10 10.01)'
|
108
|
+
POINT_EWKT = 'SRID=4326; POINT(10 10.01)'
|
109
|
+
POINT_EWKT_WITH_DEFAULT = 'SRID=default; POINT(10 10.01)'
|
110
|
+
POINT_WKB = "0101000000000000000000244085EB51B81E052440"
|
111
|
+
POINT_WKB_BIN = "\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x24\x40\x85\xEB\x51\xB8\x1E\x05\x24\x40"
|
112
|
+
POINT_EWKB = "0101000020E6100000000000000000244085EB51B81E052440"
|
113
|
+
POINT_EWKB_BIN = "\x01\x01\x00\x00\x20\xE6\x10\x00\x00\x00\x00\x00\x00\x00\x00\x24\x40\x85\xEB\x51\xB8\x1E\x05\x24\x40"
|
114
|
+
POINT_G_LAT_LNG = "(10.01, 10)"
|
115
|
+
POINT_G_LAT_LNG_URL_VALUE = "10.01,10"
|
116
|
+
|
117
|
+
POLYGON_WKT = 'POLYGON((0 0, 1 1, 2.5 2.5, 5 5, 0 0))'
|
118
|
+
POLYGON_EWKT = 'SRID=4326; POLYGON((0 0, 1 1, 2.5 2.5, 5 5, 0 0))'
|
119
|
+
POLYGON_WKB = "
|
120
|
+
0103000000010000000500000000000000000000000000000000000000000000000000F
|
121
|
+
03F000000000000F03F0000000000000440000000000000044000000000000014400000
|
122
|
+
00000000144000000000000000000000000000000000
|
123
|
+
".gsub(/\s/, '')
|
124
|
+
POLYGON_WKB_BIN = [
|
125
|
+
"\x01\x03\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
126
|
+
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xF0\x3F\x00",
|
127
|
+
"\x00\x00\x00\x00\x00\xF0\x3F\x00\x00\x00\x00\x00\x00\x04\x40\x00\x00\x00\x00",
|
128
|
+
"\x00\x00\x04\x40\x00\x00\x00\x00\x00\x00\x14\x40\x00\x00\x00\x00\x00\x00\x14",
|
129
|
+
"\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
130
|
+
].join
|
131
|
+
POLYGON_EWKB = "
|
132
|
+
0103000020E610000001000000050000000000000000000000000000000000000000000
|
133
|
+
0000000F03F000000000000F03F00000000000004400000000000000440000000000000
|
134
|
+
1440000000000000144000000000000000000000000000000000
|
135
|
+
".gsub(/\s/, '')
|
136
|
+
POLYGON_EWKB_BIN = [
|
137
|
+
"\x01\x03\x00\x00\x20\xE6\x10\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00",
|
138
|
+
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
139
|
+
"\x00\x00\x00\x00\x00\xF0\x3F\x00\x00\x00\x00\x00\x00\xF0\x3F\x00\x00",
|
140
|
+
"\x00\x00\x00\x00\x04\x40\x00\x00\x00\x00\x00\x00\x04\x40\x00\x00\x00",
|
141
|
+
"\x00\x00\x00\x14\x40\x00\x00\x00\x00\x00\x00\x14\x40\x00\x00\x00\x00",
|
142
|
+
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
143
|
+
].join
|
144
|
+
|
145
|
+
POLYGON_WITH_INTERIOR_RING = "POLYGON((0 0, 5 0, 5 5, 0 5, 0 0),(4 4, 4 1, 1 1, 1 4, 4 4))"
|
146
|
+
|
147
|
+
LINESTRING_WKT = "LINESTRING (0 0, 5 5, 5 10, 10 10)"
|
148
|
+
|
149
|
+
GEOMETRYCOLLECTION_WKT = 'GEOMETRYCOLLECTION (
|
150
|
+
MULTIPOLYGON (
|
151
|
+
((0 0, 1 0, 1 1, 0 1, 0 0)),
|
152
|
+
(
|
153
|
+
(10 10, 10 14, 14 14, 14 10, 10 10),
|
154
|
+
(11 11, 11 12, 12 12, 12 11, 11 11)
|
155
|
+
)
|
156
|
+
),
|
157
|
+
POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0)),
|
158
|
+
POLYGON ((0 0, 5 0, 5 5, 0 5, 0 0), (4 4, 4 1, 1 1, 1 4, 4 4)),
|
159
|
+
MULTILINESTRING ((0 0, 2 3), (10 10, 3 4)),
|
160
|
+
LINESTRING (0 0, 2 3),
|
161
|
+
MULTIPOINT ((0 0), (2 3)),
|
162
|
+
POINT (9 0)
|
163
|
+
)'
|
164
|
+
|
165
|
+
BOUNDS_G_LAT_LNG = "((0.1, 0.1), (5.2, 5.2))"
|
166
|
+
BOUNDS_G_LAT_LNG_URL_VALUE = '0.1,0.1,5.2,5.2'
|
167
|
+
|
168
|
+
class << self
|
169
|
+
def load_models(*args)
|
170
|
+
options = args.extract_options!
|
171
|
+
|
172
|
+
args.each do |model|
|
173
|
+
model = model.to_s
|
174
|
+
klass = model.classify
|
175
|
+
|
176
|
+
ActiveSupport::Dependencies.load_file(BASE_PATH.join("models/#{model}.rb"), [ klass ])
|
177
|
+
|
178
|
+
ActiveRecord::Base.silence do
|
179
|
+
fixtures model.pluralize
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def load_default_models
|
185
|
+
load_models(:foo, :bar)
|
186
|
+
|
187
|
+
Foo.class_eval do
|
188
|
+
has_many_spatially :foos
|
189
|
+
has_many_spatially :bars
|
190
|
+
end
|
191
|
+
|
192
|
+
Bar.class_eval do
|
193
|
+
has_many_spatially :foos
|
194
|
+
has_many_spatially :bars
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def after_suite
|
199
|
+
ActiveSupport::Dependencies.clear
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def setup
|
204
|
+
if ActiveRecord::Base.logger
|
205
|
+
ActiveRecord::Base.logger.debug("Beginning tests for #{self.class.name}##{self.method_name}")
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def assert_saneness_of_point(point)
|
210
|
+
assert_kind_of(Geos::Point, point)
|
211
|
+
assert_equal(10.01, point.lat)
|
212
|
+
assert_equal(10, point.lng)
|
213
|
+
end
|
214
|
+
|
215
|
+
def assert_saneness_of_polygon(polygon)
|
216
|
+
assert_kind_of(Geos::Polygon, polygon)
|
217
|
+
cs = polygon.exterior_ring.coord_seq
|
218
|
+
assert_equal([
|
219
|
+
[ 0, 0 ],
|
220
|
+
[ 1, 1 ],
|
221
|
+
[ 2.5, 2.5 ],
|
222
|
+
[ 5, 5 ],
|
223
|
+
[ 0, 0 ]
|
224
|
+
], cs.to_a)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
module ActiveRecord
|
229
|
+
class SQLCounter
|
230
|
+
cattr_accessor :ignored_sql
|
231
|
+
self.ignored_sql = [
|
232
|
+
/^PRAGMA (?!(table_info))/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/,
|
233
|
+
/^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/,
|
234
|
+
/^SHOW max_identifier_length/, /^BEGIN/, /^COMMIT/, /^ROLLBACK/, /\WFROM pg_/
|
235
|
+
]
|
236
|
+
|
237
|
+
cattr_accessor :log
|
238
|
+
self.log = []
|
239
|
+
|
240
|
+
attr_reader :ignore
|
241
|
+
|
242
|
+
def initialize(ignore = self.class.ignored_sql)
|
243
|
+
@ignore = ignore
|
244
|
+
end
|
245
|
+
|
246
|
+
def call(name, start, finish, message_id, values)
|
247
|
+
sql = values[:sql]
|
248
|
+
|
249
|
+
# FIXME: this seems bad. we should probably have a better way to indicate
|
250
|
+
# the query was cached
|
251
|
+
return if 'CACHE' == values[:name] || ignore.any? { |x| x =~ sql }
|
252
|
+
self.class.log << sql
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
ActiveSupport::Notifications.subscribe('sql.active_record', SQLCounter.new)
|
257
|
+
end
|
258
|
+
|
259
|
+
class SpatialTestRunner < MiniTest::Reporters::SpecReporter
|
260
|
+
def before_suite(suite)
|
261
|
+
super(suite)
|
262
|
+
suite.before_suite if suite.respond_to?(:before_suite)
|
263
|
+
end
|
264
|
+
|
265
|
+
def after_suite(suite)
|
266
|
+
super(suite)
|
267
|
+
suite.after_suite if suite.respond_to?(:after_suite)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
MiniTest::Reporters.use!(SpatialTestRunner.new)
|
272
|
+
|