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.
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
+