activerecord-spatial 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +16 -0
  3. data/Gemfile +21 -0
  4. data/Guardfile +17 -0
  5. data/MIT-LICENSE +23 -0
  6. data/README.rdoc +169 -0
  7. data/Rakefile +28 -0
  8. data/activerecord-spatial.gemspec +26 -0
  9. data/lib/activerecord-spatial.rb +32 -0
  10. data/lib/activerecord-spatial/active_record.rb +14 -0
  11. data/lib/activerecord-spatial/active_record/connection_adapters/postgresql/adapter_extensions.rb +36 -0
  12. data/lib/activerecord-spatial/active_record/connection_adapters/postgresql/postgis.rb +24 -0
  13. data/lib/activerecord-spatial/active_record/connection_adapters/postgresql/unknown_srid.rb +21 -0
  14. data/lib/activerecord-spatial/active_record/models/geography_column.rb +17 -0
  15. data/lib/activerecord-spatial/active_record/models/geometry_column.rb +17 -0
  16. data/lib/activerecord-spatial/active_record/models/spatial_column.rb +22 -0
  17. data/lib/activerecord-spatial/active_record/models/spatial_ref_sys.rb +20 -0
  18. data/lib/activerecord-spatial/associations.rb +292 -0
  19. data/lib/activerecord-spatial/spatial_columns.rb +345 -0
  20. data/lib/activerecord-spatial/spatial_function.rb +201 -0
  21. data/lib/activerecord-spatial/spatial_scope_constants.rb +114 -0
  22. data/lib/activerecord-spatial/spatial_scopes.rb +297 -0
  23. data/lib/activerecord-spatial/version.rb +5 -0
  24. data/lib/tasks/test.rake +45 -0
  25. data/test/accessors_geographies_tests.rb +149 -0
  26. data/test/accessors_geometries_tests.rb +151 -0
  27. data/test/adapter_tests.rb +44 -0
  28. data/test/associations_tests.rb +656 -0
  29. data/test/database.yml +17 -0
  30. data/test/fixtures/bars.yml +16 -0
  31. data/test/fixtures/blorts.yml +37 -0
  32. data/test/fixtures/foo3ds.yml +17 -0
  33. data/test/fixtures/foo_geographies.yml +16 -0
  34. data/test/fixtures/foos.yml +16 -0
  35. data/test/fixtures/zortables.yml +36 -0
  36. data/test/geography_column_tests.rb +40 -0
  37. data/test/geometry_column_tests.rb +40 -0
  38. data/test/models/bar.rb +17 -0
  39. data/test/models/blort.rb +12 -0
  40. data/test/models/foo.rb +17 -0
  41. data/test/models/foo3d.rb +17 -0
  42. data/test/models/foo_geography.rb +16 -0
  43. data/test/models/zortable.rb +17 -0
  44. data/test/spatial_scopes_geographies_tests.rb +106 -0
  45. data/test/spatial_scopes_tests.rb +444 -0
  46. data/test/test_helper.rb +272 -0
  47. metadata +138 -0
@@ -0,0 +1,5 @@
1
+
2
+ module ActiveRecordSpatial
3
+ VERSION = '0.0.1'
4
+ end
5
+
@@ -0,0 +1,45 @@
1
+
2
+ namespace :test do
3
+ desc "Dumps data from the geometry_columns and spatial_ref_sys tables."
4
+ task :postgis_dump => :environment do
5
+ abcs = ActiveRecord::Base.configurations
6
+ ENV['PGHOST'] = abcs[Rails.env]["host"] if abcs[Rails.env]["host"]
7
+ ENV['PGPORT'] = abcs[Rails.env]["port"].to_s if abcs[Rails.env]["port"]
8
+ ENV['PGPASSWORD'] = abcs[Rails.env]["password"].to_s if abcs[Rails.env]["password"]
9
+ search_path = abcs[Rails.env]["schema_search_path"]
10
+ unless search_path.blank?
11
+ search_path = search_path.split(",").map{|search_path| "--schema=#{search_path.strip}" }.join(" ")
12
+ end
13
+
14
+ tables = %w{ geometry_columns spatial_ref_sys }.select do |table|
15
+ ActiveRecord::Base.connection.table_exists?(table) &&
16
+ !ActiveRecord::Base.connection.view_exists?(table)
17
+ end
18
+
19
+ pp tables
20
+
21
+ unless tables.empty?
22
+ `pg_dump -i -U "#{abcs[Rails.env]["username"]}" --data-only -t #{tables.join(' -t ')} -x -O -f db/#{Rails.env}_postgis_tables.sql #{search_path} #{abcs[Rails.env]["database"]}`
23
+ else
24
+ File.open("db/#{Rails.env}_postgis_tables.sql", 'w') do |fp|
25
+ fp.puts "-- empty, do geometry_columns and spatial_ref_sys tables exist?"
26
+ end
27
+ end
28
+ end
29
+
30
+ desc "Loads the geometry_columns and spatial_ref_sys tables."
31
+ task :postgis_load => :environment do
32
+ abcs = ActiveRecord::Base.configurations
33
+ ENV['PGHOST'] = abcs["test"]["host"] if abcs["test"]["host"]
34
+ ENV['PGPORT'] = abcs["test"]["port"].to_s if abcs["test"]["port"]
35
+ ENV['PGPASSWORD'] = abcs["test"]["password"].to_s if abcs["test"]["password"]
36
+
37
+ `psql -U "#{abcs["test"]["username"]}" -f #{Rails.root}/db/#{Rails.env}_postgis_tables.sql #{abcs["test"]["database"]}`
38
+ end
39
+
40
+ desc "Dumps and loads the geometry_columns and spatial_ref_sys tables."
41
+ task :postgis_clone => [ :postgis_dump, :postgis_load ]
42
+ end
43
+
44
+ Rake::Task['test:prepare'].enhance(['test:postgis_clone'])
45
+
@@ -0,0 +1,149 @@
1
+
2
+ $: << File.dirname(__FILE__)
3
+ require 'test_helper'
4
+
5
+ class AccessorsGeographiesTests < ActiveRecordSpatialTestCase
6
+ def self.before_suite
7
+ load_models(:foo_geography)
8
+ end
9
+
10
+ def test_accessors
11
+ foo = FooGeography.find(1)
12
+
13
+ ActiveRecordSpatial::SpatialColumns::SPATIAL_COLUMN_OUTPUT_FORMATS.each do |format|
14
+ assert(foo.respond_to?("the_geom_#{format}"))
15
+ assert(foo.respond_to?("the_other_geom_#{format}"))
16
+ end
17
+ end
18
+
19
+ def test_without_accessor
20
+ foo = FooGeography.find(1)
21
+ assert_kind_of(String, foo.the_geom)
22
+ end
23
+
24
+ def test_geos_accessor
25
+ foo = FooGeography.find(1)
26
+ assert_kind_of(Geos::Point, foo.the_geom_geos)
27
+ end
28
+
29
+ def test_wkt_accessor
30
+ foo = FooGeography.find(1)
31
+ assert_kind_of(String, foo.the_geom_wkt)
32
+ assert_match(/^POINT\s*\(0\.0+\s+0\.0+\)$/, foo.the_geom_wkt)
33
+ end
34
+
35
+ def test_wkb_accessor
36
+ foo = FooGeography.find(1)
37
+ assert_kind_of(String, foo.the_geom_wkb)
38
+ assert_match(/^[A-F0-9]+$/, foo.the_geom_wkb)
39
+ end
40
+
41
+ def test_ewkt_accessor
42
+ foo = FooGeography.find(1)
43
+ assert_kind_of(String, foo.the_geom_ewkt)
44
+ assert_match(/^SRID=\d+;POINT\s*\(0\.0+\s+0\.0+\)$/, foo.the_geom_ewkt)
45
+ end
46
+
47
+ def test_ewkb_accessor
48
+ foo = FooGeography.find(1)
49
+ assert_kind_of(String, foo.the_geom_ewkb)
50
+ assert(/^[A-F0-9]+$/, foo.the_geom_wkb)
51
+ end
52
+
53
+ def test_wkb_bin_accessor
54
+ foo = FooGeography.find(1)
55
+ assert_kind_of(String, foo.the_geom_wkb_bin)
56
+ end
57
+
58
+ def test_ewkb_bin_accessor
59
+ foo = FooGeography.find(1)
60
+ assert_kind_of(String, foo.the_geom_ewkb_bin)
61
+ end
62
+
63
+ def test_geos_create
64
+ foo = FooGeography.create!(
65
+ :name => 'test_geos_create',
66
+ :the_geom => Geos.read(POINT_WKT)
67
+ )
68
+
69
+ foo.reload
70
+ assert_saneness_of_point(foo.the_geom_geos)
71
+ end
72
+
73
+ def test_wkt_create
74
+ foo = FooGeography.create!(
75
+ :name => 'test_wkt_create',
76
+ :the_geom => POINT_WKT
77
+ )
78
+
79
+ foo.reload
80
+ assert_saneness_of_point(foo.the_geom_geos)
81
+ end
82
+
83
+ def test_wkb_create
84
+ foo = FooGeography.create!(
85
+ :name => 'test_wkb_create',
86
+ :the_geom => POINT_WKB
87
+ )
88
+
89
+ foo.reload
90
+ assert_saneness_of_point(foo.the_geom_geos)
91
+ end
92
+
93
+ def test_ewkt_create_with_srid_4326
94
+ foo = FooGeography.create!(
95
+ :name => 'test_ewkt_create_with_srid_4326',
96
+ :the_other_geom => POINT_EWKT
97
+ )
98
+
99
+ foo.reload
100
+ assert_saneness_of_point(foo.the_other_geom_geos)
101
+ end
102
+
103
+ def test_create_with_no_srid_converting_to_4326
104
+ foo = FooGeography.create!(
105
+ :name => 'test_ewkt_create_with_no_srid_converting_to_4326',
106
+ :the_other_geom => POINT_WKT
107
+ )
108
+
109
+ foo.reload
110
+ assert_saneness_of_point(foo.the_other_geom_geos)
111
+ end
112
+
113
+ def test_create_with_no_srid_converting_to_minus_1
114
+ foo = FooGeography.create!(
115
+ :name => 'test_ewkt_create_with_no_srid_converting_to_minus_1',
116
+ :the_geom => POINT_EWKT
117
+ )
118
+
119
+ foo.reload
120
+ assert_saneness_of_point(foo.the_geom_geos)
121
+ end
122
+
123
+ def test_create_with_converting_from_900913_to_4326
124
+ FooGeography.create!(
125
+ :name => 'test_create_with_converting_from_900913_to_4326',
126
+ :the_other_geom => "SRID=900913; #{POINT_WKT}"
127
+ )
128
+ end
129
+
130
+ def test_ewkt_create_with_srid_default
131
+ foo = FooGeography.create!(
132
+ :name => 'test_ewkt_create_with_srid_default',
133
+ :the_other_geom => POINT_EWKT_WITH_DEFAULT
134
+ )
135
+
136
+ foo.reload
137
+ assert_saneness_of_point(foo.the_other_geom_geos)
138
+ end
139
+
140
+ def test_ewkb_create
141
+ foo = FooGeography.create!(
142
+ :name => 'test_ewkb_create',
143
+ :the_other_geom => POINT_EWKB
144
+ )
145
+
146
+ foo.reload
147
+ assert_saneness_of_point(foo.the_other_geom_geos)
148
+ end
149
+ end
@@ -0,0 +1,151 @@
1
+
2
+ $: << File.dirname(__FILE__)
3
+ require 'test_helper'
4
+
5
+ class AccessorsGeometriesTests < ActiveRecordSpatialTestCase
6
+ def self.before_suite
7
+ load_models(:foo)
8
+ end
9
+
10
+ def test_accessors
11
+ foo = Foo.find(1)
12
+
13
+ ActiveRecordSpatial::SpatialColumns::SPATIAL_COLUMN_OUTPUT_FORMATS.each do |format|
14
+ assert(foo.respond_to?("the_geom_#{format}"))
15
+ assert(foo.respond_to?("the_other_geom_#{format}"))
16
+ end
17
+ end
18
+
19
+ def test_without_accessor
20
+ foo = Foo.find(1)
21
+ assert_kind_of(String, foo.the_geom)
22
+ end
23
+
24
+ def test_geos_accessor
25
+ foo = Foo.find(1)
26
+ assert_kind_of(Geos::Point, foo.the_geom_geos)
27
+ end
28
+
29
+ def test_wkt_accessor
30
+ foo = Foo.find(1)
31
+ assert_kind_of(String, foo.the_geom_wkt)
32
+ assert_match(/^POINT\s*\(0\.0+\s+0\.0+\)$/, foo.the_geom_wkt)
33
+ end
34
+
35
+ def test_wkb_accessor
36
+ foo = Foo.find(1)
37
+ assert_kind_of(String, foo.the_geom_wkb)
38
+ assert_match(/^[A-F0-9]+$/, foo.the_geom_wkb)
39
+ end
40
+
41
+ def test_ewkt_accessor
42
+ foo = Foo.find(1)
43
+ assert_kind_of(String, foo.the_geom_ewkt)
44
+ assert_match(/^SRID=\d+;POINT\s*\(0\.0+\s+0\.0+\)$/, foo.the_geom_ewkt)
45
+ end
46
+
47
+ def test_ewkb_accessor
48
+ foo = Foo.find(1)
49
+ assert_kind_of(String, foo.the_geom_ewkb)
50
+ assert(/^[A-F0-9]+$/, foo.the_geom_wkb)
51
+ end
52
+
53
+ def test_wkb_bin_accessor
54
+ foo = Foo.find(1)
55
+ assert_kind_of(String, foo.the_geom_wkb_bin)
56
+ end
57
+
58
+ def test_ewkb_bin_accessor
59
+ foo = Foo.find(1)
60
+ assert_kind_of(String, foo.the_geom_ewkb_bin)
61
+ end
62
+
63
+ def test_geos_create
64
+ foo = Foo.create!(
65
+ :name => 'test_geos_create',
66
+ :the_geom => Geos.read(POINT_WKT)
67
+ )
68
+
69
+ foo.reload
70
+ assert_saneness_of_point(foo.the_geom_geos)
71
+ end
72
+
73
+ def test_wkt_create
74
+ foo = Foo.create!(
75
+ :name => 'test_wkt_create',
76
+ :the_geom => POINT_WKT
77
+ )
78
+
79
+ foo.reload
80
+ assert_saneness_of_point(foo.the_geom_geos)
81
+ end
82
+
83
+ def test_wkb_create
84
+ foo = Foo.create!(
85
+ :name => 'test_wkb_create',
86
+ :the_geom => POINT_WKB
87
+ )
88
+
89
+ foo.reload
90
+ assert_saneness_of_point(foo.the_geom_geos)
91
+ end
92
+
93
+ def test_ewkt_create_with_srid_4326
94
+ foo = Foo.create!(
95
+ :name => 'test_ewkt_create_with_srid_4326',
96
+ :the_other_geom => POINT_EWKT
97
+ )
98
+
99
+ foo.reload
100
+ assert_saneness_of_point(foo.the_other_geom_geos)
101
+ end
102
+
103
+ def test_create_with_no_srid_converting_to_4326
104
+ foo = Foo.create!(
105
+ :name => 'test_ewkt_create_with_no_srid_converting_to_4326',
106
+ :the_other_geom => POINT_WKT
107
+ )
108
+
109
+ foo.reload
110
+ assert_saneness_of_point(foo.the_other_geom_geos)
111
+ end
112
+
113
+ def test_create_with_no_srid_converting_to_minus_1
114
+ foo = Foo.create!(
115
+ :name => 'test_ewkt_create_with_no_srid_converting_to_minus_1',
116
+ :the_geom => POINT_EWKT
117
+ )
118
+
119
+ foo.reload
120
+ assert_saneness_of_point(foo.the_geom_geos)
121
+ end
122
+
123
+ def test_create_with_converting_from_900913_to_4326
124
+ assert_raise(ActiveRecordSpatial::GeometryColumns::CantConvertSRID) do
125
+ Foo.create!(
126
+ :name => 'test_create_with_converting_from_900913_to_4326',
127
+ :the_other_geom => "SRID=900913; #{POINT_WKT}"
128
+ )
129
+ end
130
+ end
131
+
132
+ def test_ewkt_create_with_srid_default
133
+ foo = Foo.create!(
134
+ :name => 'test_ewkt_create_with_srid_default',
135
+ :the_other_geom => POINT_EWKT_WITH_DEFAULT
136
+ )
137
+
138
+ foo.reload
139
+ assert_saneness_of_point(foo.the_other_geom_geos)
140
+ end
141
+
142
+ def test_ewkb_create
143
+ foo = Foo.create!(
144
+ :name => 'test_ewkb_create',
145
+ :the_other_geom => POINT_EWKB
146
+ )
147
+
148
+ foo.reload
149
+ assert_saneness_of_point(foo.the_other_geom_geos)
150
+ end
151
+ end
@@ -0,0 +1,44 @@
1
+
2
+ $: << File.dirname(__FILE__)
3
+ require 'test_helper'
4
+
5
+ class AdapterTests < ActiveRecordSpatialTestCase
6
+ def self.before_suite
7
+ load_models(:foo)
8
+ end
9
+
10
+ def test_simplified_type
11
+ geometry_columns = Foo.columns.select do |c|
12
+ c.type == :geometry
13
+ end
14
+
15
+ other_columns = Foo.columns.select do |c|
16
+ c.type != :geometry
17
+ end
18
+
19
+ assert_equal(2, geometry_columns.length)
20
+ assert_equal(2, other_columns.length)
21
+ end
22
+ end
23
+
24
+ if ActiveRecordSpatial.geography_columns?
25
+ class AdapterWithGeographyTests < ActiveRecordSpatialTestCase
26
+ def self.before_suite
27
+ load_models(:foo_geography)
28
+ end
29
+
30
+ def test_simplified_type_geography
31
+ geography_columns = FooGeography.columns.select do |c|
32
+ c.type == :geography
33
+ end
34
+
35
+ other_columns = FooGeography.columns.select do |c|
36
+ c.type != :geography
37
+ end
38
+
39
+ assert_equal(2, geography_columns.length)
40
+ assert_equal(2, other_columns.length)
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,656 @@
1
+
2
+ $: << File.dirname(__FILE__)
3
+ require 'test_helper'
4
+
5
+ class DefaultIntersectsRelationshipTest < ActiveRecordSpatialTestCase
6
+ def self.before_suite
7
+ load_models(:foo, :bar)
8
+
9
+ Foo.class_eval do
10
+ has_many_spatially :bars
11
+ end
12
+ end
13
+
14
+ def test_reflection
15
+ assert_equal(:has_many, Foo.reflections[:bars].macro)
16
+ assert_equal(:intersects, Foo.reflections[:bars].options[:relationship])
17
+ end
18
+
19
+ def test_association
20
+ assert_equal([ 3 ], Foo.first.bars.collect(&:id).sort)
21
+ end
22
+ end
23
+
24
+ class RelationshipsTest < ActiveRecordSpatialTestCase
25
+ def self.before_suite
26
+ load_models(:foo, :bar)
27
+ end
28
+
29
+ {
30
+ :contains => [],
31
+ :containsproperly => [],
32
+ :covers => [],
33
+ :coveredby => [ 3 ],
34
+ :crosses => [],
35
+ :disjoint => [ 1, 2 ],
36
+ :equals => [],
37
+ :intersects => [ 3 ],
38
+ :orderingequals => [],
39
+ :overlaps => [],
40
+ :touches => [],
41
+ :within => [ 3 ],
42
+ :'3dintersects' => [ 3 ]
43
+ }.each do |relationship, ids|
44
+ define_method("test_#{relationship}") do
45
+ skip("ST_#{relationship} is unavailable") unless Foo.respond_to?("st_#{relationship}")
46
+
47
+ Foo.reflections.delete(:bars)
48
+
49
+ Foo.class_eval do
50
+ has_many_spatially :bars, :relationship => relationship
51
+ end
52
+
53
+ assert_equal(:has_many, Foo.reflections[:bars].macro)
54
+ assert_equal(relationship, Foo.reflections[:bars].options[:relationship])
55
+ assert_equal(ids, Foo.first.bars.collect(&:id).sort)
56
+ end
57
+ end
58
+ end
59
+
60
+ class RelationshipsWithSelfTest < ActiveRecordSpatialTestCase
61
+ def self.before_suite
62
+ load_models(:foo, :bar)
63
+ end
64
+
65
+ {
66
+ :contains => [ 1 ],
67
+ :containsproperly => [ 1 ],
68
+ :covers => [ 1 ],
69
+ :coveredby => [ 1, 3 ],
70
+ :crosses => [],
71
+ :disjoint => [ 2 ],
72
+ :equals => [ 1 ],
73
+ :intersects => [ 1, 3 ],
74
+ :orderingequals => [ 1 ],
75
+ :overlaps => [],
76
+ :touches => [],
77
+ :within => [ 1, 3 ],
78
+ :'3dintersects' => [ 1, 3 ]
79
+ }.each do |relationship, ids|
80
+ define_method("test_#{relationship}") do
81
+ skip("ST_#{relationship} is unavailable") unless Foo.respond_to?("st_#{relationship}")
82
+
83
+ Foo.reflections.delete(:foos)
84
+
85
+ Foo.class_eval do
86
+ has_many_spatially :foos, :relationship => relationship
87
+ end
88
+
89
+ assert_equal(:has_many, Foo.reflections[:foos].macro)
90
+ assert_equal(relationship, Foo.reflections[:foos].options[:relationship])
91
+ assert_equal(ids, Foo.first.foos.collect(&:id).sort)
92
+ end
93
+ end
94
+ end
95
+
96
+ class RelationshipsWithForeignGeomTest < ActiveRecordSpatialTestCase
97
+ def self.before_suite
98
+ load_models(:foo, :bar)
99
+ end
100
+
101
+ {
102
+ :contains => [],
103
+ :containsproperly => [],
104
+ :covers => [],
105
+ :coveredby => [ 3 ],
106
+ :crosses => [],
107
+ :disjoint => [ 1, 2 ],
108
+ :equals => [],
109
+ :intersects => [ 3 ],
110
+ :orderingequals => [],
111
+ :overlaps => [],
112
+ :touches => [],
113
+ :within => [ 3 ],
114
+ :'3dintersects' => [ 3 ]
115
+ }.each do |relationship, ids|
116
+ define_method("test_#{relationship}") do
117
+ skip("ST_#{relationship} is unavailable") unless Foo.respond_to?("st_#{relationship}")
118
+
119
+ Foo.reflections.delete(:bars)
120
+
121
+ Foo.class_eval do
122
+ has_many_spatially :bars,
123
+ :relationship => relationship,
124
+ :foreign_geom => :the_other_geom
125
+ end
126
+
127
+ assert_equal(:has_many, Foo.reflections[:bars].macro)
128
+ assert_equal(relationship, Foo.reflections[:bars].options[:relationship])
129
+ assert_equal(:the_geom, Foo.reflections[:bars].options[:geom])
130
+ assert_equal(:the_other_geom, Foo.reflections[:bars].options[:foreign_geom])
131
+ assert_equal(ids, Foo.first.bars.collect(&:id).sort)
132
+ end
133
+ end
134
+ end
135
+
136
+ class RelationshipsWithGeomTest < ActiveRecordSpatialTestCase
137
+ def self.before_suite
138
+ load_models(:foo, :bar)
139
+ end
140
+
141
+ {
142
+ :contains => [],
143
+ :containsproperly => [],
144
+ :covers => [],
145
+ :coveredby => [ 3 ],
146
+ :crosses => [],
147
+ :disjoint => [ 1, 2 ],
148
+ :equals => [],
149
+ :intersects => [ 3 ],
150
+ :orderingequals => [],
151
+ :overlaps => [],
152
+ :touches => [ 3 ],
153
+ :within => [],
154
+ :'3dintersects' => [ 3 ]
155
+ }.each do |relationship, ids|
156
+ define_method("test_#{relationship}") do
157
+ skip("ST_#{relationship} is unavailable") unless Foo.respond_to?("st_#{relationship}")
158
+
159
+ Foo.reflections.delete(:bars)
160
+
161
+ Foo.class_eval do
162
+ has_many_spatially :bars,
163
+ :relationship => relationship,
164
+ :geom => :the_other_geom
165
+ end
166
+
167
+ assert_equal(:has_many, Foo.reflections[:bars].macro)
168
+ assert_equal(relationship, Foo.reflections[:bars].options[:relationship])
169
+ assert_equal(:the_other_geom, Foo.reflections[:bars].options[:geom])
170
+ assert_equal(:the_geom, Foo.reflections[:bars].options[:foreign_geom])
171
+ assert_equal(ids, Foo.first.bars.collect(&:id).sort)
172
+ end
173
+ end
174
+ end
175
+
176
+ class CountsTest < ActiveRecordSpatialTestCase
177
+ def self.before_suite
178
+ load_default_models
179
+ end
180
+
181
+ def test_count
182
+ assert_equal(2, Foo.last.bars.count)
183
+ assert_equal(2, Foo.last.foos.count)
184
+ end
185
+ end
186
+
187
+ class WithCounterSqlTest < ActiveRecordSpatialTestCase
188
+ def self.before_suite
189
+ load_models(:foo, :bar)
190
+ end
191
+
192
+ def test_should_fail
193
+ assert_raise(ArgumentError) do
194
+ Foo.class_eval do
195
+ has_many_spatially :bars,
196
+ :class_name => 'Bar',
197
+ :counter_sql => "SELECT COUNT(*) bars.* FROM bars"
198
+ end
199
+ end
200
+ end
201
+ end
202
+
203
+ class ScopeOptionsTest < ActiveRecordSpatialTestCase
204
+ def self.before_suite
205
+ load_models(:foo, :bar)
206
+
207
+ Foo.class_eval do
208
+ has_many_spatially :bars,
209
+ :class_name => 'Bar',
210
+ :scope_options => {
211
+ :use_index => false
212
+ }
213
+ end
214
+ end
215
+
216
+ def test_use_index_false
217
+ assert_sql(/_ST_intersects\(/) do
218
+ Foo.first.bars.length
219
+ end
220
+ end
221
+ end
222
+
223
+ class PreloadTest < ActiveRecordSpatialTestCase
224
+ def self.before_suite
225
+ load_default_models
226
+ end
227
+
228
+ def test_without_eager_loading
229
+ values = nil
230
+ assert_queries(4) do
231
+ assert_sql(/ST_intersects\('#{REGEXP_WKB_HEX}'::geometry, "bars"\."the_geom"/) do
232
+ values = Foo.all.collect do |foo|
233
+ foo.bars.length
234
+ end
235
+ end
236
+ end
237
+
238
+ assert_equal([ 1, 1, 2], values)
239
+ end
240
+
241
+ def test_with_eager_loading
242
+ values = nil
243
+ assert_queries(2) do
244
+ assert_sql(/SELECT "bars"\.\*, array_to_string\(array_agg\("__spatial_ids_join__"."id"\), ','\) AS "__spatial_ids__" FROM "bars" INNER JOIN "foos" AS "__spatial_ids_join__" ON \(ST_intersects\("__spatial_ids_join__"."the_geom", "bars"."the_geom"\)\) WHERE "__spatial_ids_join__"\."id" IN \(.+\) GROUP BY "bars"\."id"/) do
245
+ values = Foo.includes(:bars).all.collect do |foo|
246
+ foo.bars.length
247
+ end
248
+ end
249
+ end
250
+
251
+ assert_equal([ 1, 1, 2 ], values)
252
+ end
253
+ end
254
+
255
+ class PreloadWithOtherGeomTest < ActiveRecordSpatialTestCase
256
+ def self.before_suite
257
+ load_models(:foo, :bar)
258
+
259
+ Foo.class_eval do
260
+ has_many_spatially :bars,
261
+ :class_name => 'Bar',
262
+ :geom => :the_other_geom
263
+ end
264
+ end
265
+
266
+ def test_without_eager_loading
267
+ values = nil
268
+ assert_queries(4) do
269
+ assert_sql(/ST_intersects\(ST_SetSRID\('#{REGEXP_WKB_HEX}'::geometry, #{ActiveRecordSpatial::UNKNOWN_SRID}\), "bars"\."the_geom"/) do
270
+ values = Foo.order('id').all.collect do |foo|
271
+ foo.bars.length
272
+ end
273
+ end
274
+ end
275
+
276
+ assert_equal([ 1, 0, 2 ], values)
277
+ end
278
+
279
+ def test_with_eager_loading
280
+ values = nil
281
+ assert_queries(2) do
282
+ assert_sql(/SELECT "bars"\.\*, array_to_string\(array_agg\("__spatial_ids_join__"."id"\), ','\) AS "__spatial_ids__" FROM "bars" INNER JOIN "foos" AS "__spatial_ids_join__" ON \(ST_intersects\(ST_SetSRID\("__spatial_ids_join__"."the_other_geom", #{ActiveRecordSpatial::UNKNOWN_SRID}\), "bars"."the_geom"\)\) WHERE "__spatial_ids_join__"\."id" IN \(.+\) GROUP BY "bars"\."id"/) do
283
+ values = Foo.order('id').includes(:bars).all.collect do |foo|
284
+ foo.bars.length
285
+ end
286
+ end
287
+ end
288
+
289
+ assert_equal([ 1, 0, 2 ], values)
290
+ end
291
+ end
292
+
293
+ class OrderingTest < ActiveRecordSpatialTestCase
294
+ def self.before_suite
295
+ load_models(:foo, :bar)
296
+
297
+ Foo.class_eval do
298
+ has_many_spatially :bars,
299
+ :relationship => :disjoint,
300
+ :order => 'ST_area(the_geom)'
301
+ end
302
+ end
303
+
304
+ def test_ordering
305
+ assert_equal([ 1, 2 ], Foo.first.bars.collect(&:id))
306
+ end
307
+
308
+ def test_reordering
309
+ assert_equal([ 2, 1 ], Foo.first.bars.reorder('bars.id DESC').collect(&:id))
310
+ end
311
+ end
312
+
313
+ class PolymorphicAssociationsTest < ActiveRecordSpatialTestCase
314
+ def self.before_suite
315
+ load_models(:foo, :bar, :zortable)
316
+
317
+ Foo.class_eval do
318
+ has_many_spatially :zortables,
319
+ :as => :zortable
320
+ end
321
+
322
+ Bar.class_eval do
323
+ has_many_spatially :zortables,
324
+ :as => :zortable,
325
+ :geom => :the_other_geom
326
+ end
327
+ end
328
+
329
+ def test_without_eager_loading
330
+ values = nil
331
+ assert_queries(2) do
332
+ assert_sql(/ST_intersects\('#{REGEXP_WKB_HEX}'::geometry, "zortables"\."zortable_geom"/) do
333
+ values = Foo.first.zortables.collect(&:id).sort
334
+ end
335
+ end
336
+
337
+ assert_equal([ 1, 7 ], values)
338
+ end
339
+
340
+ def test_without_eager_loading_and_geom
341
+ values = nil
342
+ assert_queries(2) do
343
+ assert_sql(/ST_intersects\(ST_SetSRID\('#{REGEXP_WKB_HEX}'::geometry, #{ActiveRecordSpatial::UNKNOWN_SRID}\), "zortables"\."zortable_geom"/) do
344
+ values = Bar.first.zortables.collect(&:id).sort
345
+ end
346
+ end
347
+
348
+ assert_equal([ 6 ], values)
349
+ end
350
+
351
+ def test_with_eager_loading
352
+ values = nil
353
+ assert_queries(2) do
354
+ assert_sql(/SELECT "zortables"\.\*, array_to_string\(array_agg\("__spatial_ids_join__"."id"\), ','\) AS "__spatial_ids__" FROM "zortables" INNER JOIN "foos" AS "__spatial_ids_join__" ON \(ST_intersects\("__spatial_ids_join__"."the_geom", "zortables"."zortable_geom"\)\) WHERE "zortables"."zortable_type" = 'Foo' AND "__spatial_ids_join__"\."id" IN \(.+\) GROUP BY "zortables"\."id"/) do
355
+ values = Foo.includes(:zortables).first.zortables.collect(&:id).sort
356
+ end
357
+ end
358
+
359
+ assert_equal([ 1, 7 ], values)
360
+ end
361
+
362
+ def test_with_eager_loading_and_geom
363
+ values = nil
364
+ assert_queries(2) do
365
+ assert_sql(/SELECT "zortables"\.\*, array_to_string\(array_agg\("__spatial_ids_join__"."id"\), ','\) AS "__spatial_ids__" FROM "zortables" INNER JOIN "bars" AS "__spatial_ids_join__" ON \(ST_intersects\(ST_SetSRID\("__spatial_ids_join__"."the_other_geom", #{ActiveRecordSpatial::UNKNOWN_SRID}\), "zortables"."zortable_geom"\)\) WHERE "zortables"."zortable_type" = 'Bar' AND "__spatial_ids_join__"\."id" IN \(.+\) GROUP BY "zortables"\."id"/) do
366
+ values = Bar.includes(:zortables).first.zortables.collect(&:id).sort
367
+ end
368
+ end
369
+
370
+ assert_equal([ 6 ], values)
371
+ end
372
+ end
373
+
374
+ class PolymorphicAssociationsWithRelationshipsTest < ActiveRecordSpatialTestCase
375
+ def self.before_suite
376
+ load_models(:foo, :bar, :zortable)
377
+ end
378
+
379
+ {
380
+ :contains => [ 1 ],
381
+ :containsproperly => [ 1 ],
382
+ :covers => [ 1 ],
383
+ :coveredby => [ 1, 7 ],
384
+ :crosses => [],
385
+ :disjoint => [ 2, 3 ],
386
+ :equals => [ 1 ],
387
+ :intersects => [ 1, 7 ],
388
+ :orderingequals => [ 1 ],
389
+ :overlaps => [],
390
+ :touches => [],
391
+ :within => [ 1, 7 ],
392
+ :'3dintersects' => [ 1, 7 ]
393
+ }.each do |relationship, ids|
394
+ define_method("test_#{relationship}") do
395
+ skip("ST_#{relationship} is unavailable") unless Foo.respond_to?("st_#{relationship}")
396
+
397
+ Foo.reflections.delete(:zortables)
398
+
399
+ Foo.class_eval do
400
+ has_many_spatially :zortables,
401
+ :as => :zortable,
402
+ :relationship => relationship
403
+ end
404
+
405
+ assert_equal(ids, Foo.first.zortables.collect(&:id).sort)
406
+ assert_equal(ids, Foo.includes(:zortables).first.zortables.collect(&:id).sort)
407
+ end
408
+ end
409
+ end
410
+
411
+ class ClassNameOptionTest < ActiveRecordSpatialTestCase
412
+ def self.before_suite
413
+ load_models(:foo, :bar)
414
+
415
+ Foo.class_eval do
416
+ has_many_spatially :blops,
417
+ :class_name => 'Bar'
418
+ end
419
+ end
420
+
421
+ def test_class_name
422
+ assert_equal([ 3 ], Foo.first.blops.collect(&:id))
423
+ assert_equal([ 3 ], Foo.includes(:blops).first.blops.collect(&:id))
424
+ end
425
+ end
426
+
427
+ class ConditionsOptionTest < ActiveRecordSpatialTestCase
428
+ def self.before_suite
429
+ load_models(:foo, :bar)
430
+
431
+ Foo.class_eval do
432
+ has_many_spatially :bars,
433
+ :relationship => :disjoint,
434
+ :conditions => {
435
+ :bars => {
436
+ :id => 3
437
+ }
438
+ }
439
+ end
440
+ end
441
+
442
+ def test_conditions
443
+ assert_equal([], Foo.first.bars.collect(&:id))
444
+ assert_equal([], Foo.includes(:bars).first.bars.collect(&:id))
445
+ end
446
+ end
447
+
448
+ class IncludeOptionTest < ActiveRecordSpatialTestCase
449
+ def self.before_suite
450
+ load_models(:blort, :foo, :bar)
451
+
452
+ Foo.class_eval do
453
+ has_many :blorts
454
+ end
455
+
456
+ Bar.class_eval do
457
+ has_many_spatially :foos,
458
+ :include => :blorts
459
+ end
460
+ end
461
+
462
+ def test_includes
463
+ values = nil
464
+ assert_queries(3) do
465
+ assert_sql(/SELECT\s+"blorts"\.\*\s+FROM\s+"blorts"\s+WHERE\s+"blorts"\."foo_id"\s+IN\s+\(.+\)/) do
466
+ values = Bar.first.foos.collect(&:id)
467
+ end
468
+ end
469
+
470
+ assert_equal([ 3 ], values)
471
+ end
472
+ end
473
+
474
+ class GeomWrapperTest < ActiveRecordSpatialTestCase
475
+ def self.before_suite
476
+ load_models(:foo, :bar)
477
+
478
+ Foo.class_eval do
479
+ has_many_spatially :bars,
480
+ :class_name => 'Bar',
481
+ :geom => {
482
+ :wrapper => :envelope
483
+ }
484
+ end
485
+ end
486
+
487
+ def test_without_eager_loading
488
+ values = nil
489
+
490
+ assert_sql(/ST_intersects\(ST_envelope\('#{REGEXP_WKB_HEX}'::geometry\), "bars"."the_geom"\)/) do
491
+ values = Foo.first.bars.collect(&:id).sort
492
+ end
493
+
494
+ assert_equal([ 3 ], values)
495
+ end
496
+
497
+ def test_with_eager_loading
498
+ values = nil
499
+
500
+ assert_sql(/ST_intersects\(ST_envelope\("__spatial_ids_join__"."the_geom"\), "bars"."the_geom"\)/) do
501
+ values = Foo.includes(:bars).first.bars.collect(&:id).sort
502
+ end
503
+
504
+ assert_equal([ 3 ], values)
505
+ end
506
+ end
507
+
508
+ class ForeignGeomWrapperTest < ActiveRecordSpatialTestCase
509
+ def self.before_suite
510
+ load_models(:foo, :bar)
511
+
512
+ Foo.class_eval do
513
+ has_many_spatially :bars,
514
+ :class_name => 'Bar',
515
+ :foreign_geom => {
516
+ :wrapper => :envelope
517
+ }
518
+ end
519
+ end
520
+
521
+ def test_without_eager_loading
522
+ values = nil
523
+
524
+ assert_sql(/ST_envelope\("bars"."the_geom"\)/) do
525
+ values = Foo.first.bars.collect(&:id).sort
526
+ end
527
+
528
+ assert_equal([ 3 ], values)
529
+ end
530
+
531
+ def test_with_eager_loading
532
+ values = nil
533
+
534
+ assert_sql(/ST_intersects\("__spatial_ids_join__"."the_geom", ST_envelope\("bars"."the_geom"\)\)/) do
535
+ values = Foo.includes(:bars).first.bars.collect(&:id).sort
536
+ end
537
+
538
+ assert_equal([ 3 ], values)
539
+ end
540
+ end
541
+
542
+ class BothGeomWrapperTest < ActiveRecordSpatialTestCase
543
+ def self.before_suite
544
+ load_models(:foo, :bar)
545
+
546
+ Foo.class_eval do
547
+ has_many_spatially :bars,
548
+ :class_name => 'Bar',
549
+ :geom => {
550
+ :wrapper => :convexhull
551
+ },
552
+ :foreign_geom => {
553
+ :wrapper => :envelope
554
+ }
555
+ end
556
+ end
557
+
558
+ def test_without_eager_loading
559
+ values = nil
560
+
561
+ assert_sql(/ST_convexhull\('#{REGEXP_WKB_HEX}'::geometry\), ST_envelope\("bars"."the_geom"\)/) do
562
+ values = Foo.first.bars.collect(&:id).sort
563
+ end
564
+
565
+ assert_equal([ 3 ], values)
566
+ end
567
+
568
+ def test_with_eager_loading
569
+ values = nil
570
+
571
+ assert_sql(/ST_intersects\(ST_convexhull\("__spatial_ids_join__"."the_geom"\), ST_envelope\("bars"."the_geom"\)\)/) do
572
+ values = Foo.includes(:bars).first.bars.collect(&:id).sort
573
+ end
574
+
575
+ assert_equal([ 3 ], values)
576
+ end
577
+ end
578
+
579
+ class BothGeomWrapperWithMixedSRIDsTest < ActiveRecordSpatialTestCase
580
+ def self.before_suite
581
+ load_models(:foo, :bar)
582
+
583
+ Foo.class_eval do
584
+ has_many_spatially :bars,
585
+ :class_name => 'Bar',
586
+ :geom => {
587
+ :wrapper => :convexhull
588
+ },
589
+ :foreign_geom => {
590
+ :wrapper => :centroid,
591
+ :name => :the_other_geom
592
+ }
593
+ end
594
+ end
595
+
596
+ def test_without_eager_loading
597
+ values = nil
598
+
599
+ assert_sql(/ST_convexhull\(ST_SetSRID\('#{REGEXP_WKB_HEX}'::geometry, 4326\)\), ST_centroid\("bars"."the_other_geom"\)/) do
600
+ values = Foo.first.bars.collect(&:id).sort
601
+ end
602
+
603
+ assert_equal([ 3 ], values)
604
+ end
605
+
606
+ def test_with_eager_loading
607
+ values = nil
608
+
609
+ assert_sql(/ST_intersects\(ST_convexhull\(ST_SetSRID\("__spatial_ids_join__"."the_geom", 4326\)\), ST_centroid\("bars"."the_other_geom"\)\)/) do
610
+ values = Foo.includes(:bars).first.bars.collect(&:id).sort
611
+ end
612
+
613
+ assert_equal([ 3 ], values)
614
+ end
615
+ end
616
+
617
+ class BothGeomWrapperAndOptionsWithMixedSRIDsTest < ActiveRecordSpatialTestCase
618
+ def self.before_suite
619
+ load_models(:foo, :bar)
620
+
621
+ Foo.class_eval do
622
+ has_many_spatially :bars,
623
+ :class_name => 'Bar',
624
+ :geom => {
625
+ :wrapper => :convexhull
626
+ },
627
+ :foreign_geom => {
628
+ :wrapper => {
629
+ :buffer => 100
630
+ },
631
+ :name => :the_other_geom
632
+ }
633
+ end
634
+ end
635
+
636
+ def test_without_eager_loading
637
+ values = nil
638
+
639
+ assert_sql(/ST_convexhull\(ST_SetSRID\('#{REGEXP_WKB_HEX}'::geometry, 4326\)\), ST_buffer\("bars"."the_other_geom", 100\)/) do
640
+ values = Foo.first.bars.collect(&:id).sort
641
+ end
642
+
643
+ assert_equal([ 1, 2, 3 ], values)
644
+ end
645
+
646
+ def test_with_eager_loading
647
+ values = nil
648
+
649
+ assert_sql(/ST_intersects\(ST_convexhull\(ST_SetSRID\("__spatial_ids_join__"."the_geom", 4326\)\), ST_buffer\("bars"."the_other_geom", 100\)\)/) do
650
+ values = Foo.includes(:bars).first.bars.collect(&:id).sort
651
+ end
652
+
653
+ assert_equal([ 1, 2, 3 ], values)
654
+ end
655
+ end
656
+