rgeo-activerecord 0.2.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +12 -0
- data/README.rdoc +2 -2
- data/Version +1 -1
- data/lib/rgeo/active_record.rb +19 -3
- data/lib/rgeo/active_record/{ar_modifications.rb → ar_factory_settings.rb} +0 -38
- data/lib/rgeo/active_record/arel_spatial_queries.rb +250 -0
- data/lib/rgeo/active_record/common_adapter_elements.rb +226 -0
- data/lib/rgeo/active_record/spatial_expressions.rb +314 -0
- data/lib/rgeo/active_record/task_hacker.rb +9 -4
- data/lib/rgeo/active_record/{arel_modifications.rb → version.rb} +12 -34
- data/test/tc_basic.rb +5 -0
- metadata +9 -7
- data/lib/rgeo/active_record/common.rb +0 -148
data/History.rdoc
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
=== 0.3.0 / 2011-01-26
|
2
|
+
|
3
|
+
* Experimental support for complex spatial queries. (Requires Arel 2.1, which is expected to be released with Rails 3.1.) Currently, only a low-level Arel-based interface is supported.
|
4
|
+
* Better support for geography types in PostGIS.
|
5
|
+
* Adapters can now define additional column constructors.
|
6
|
+
* Support for spatial column constructors on change_table.
|
7
|
+
* Fixed column type inference for some cases where the column included Z and/or M.
|
8
|
+
* IS NULL predicates now work properly with spatial types.
|
9
|
+
* Preferred attribute type is now :spatial rather than :geometry.
|
10
|
+
* The gem version is now accessible via an api.
|
11
|
+
* Some code reorganization.
|
12
|
+
|
1
13
|
=== 0.2.4 / 2011-01-13
|
2
14
|
|
3
15
|
* Fixed a problem that caused a hang during rake db:rollback, as well as probably certain other functions that use ActiveRecord::Base directly rather than a subclass. (Reported by Alexander Graefe.)
|
data/README.rdoc
CHANGED
@@ -31,8 +31,8 @@ Generally, \ActiveRecord adapters which depend on this module should be
|
|
31
31
|
installed as gems, and they will install this module automatically as
|
32
32
|
a dependency. However, you can also install it manually as a gem:
|
33
33
|
|
34
|
-
|
35
|
-
|
34
|
+
gem install rgeo
|
35
|
+
gem install rgeo-activerecord
|
36
36
|
|
37
37
|
See the README for the "rgeo" gem, a required dependency, for further
|
38
38
|
installation information.
|
data/Version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/rgeo/active_record.rb
CHANGED
@@ -60,7 +60,23 @@ module RGeo
|
|
60
60
|
end
|
61
61
|
|
62
62
|
|
63
|
+
# The rgeo-activerecord gem installs several patches to Arel to provide
|
64
|
+
# support for spatial queries.
|
65
|
+
|
66
|
+
module Arel
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# The rgeo-activerecord gem installs several patches to ActiveRecord
|
71
|
+
# to support services needed by spatial adapters.
|
72
|
+
|
73
|
+
module ActiveRecord
|
74
|
+
end
|
75
|
+
|
76
|
+
|
63
77
|
# Implementation files
|
64
|
-
require 'rgeo/active_record/
|
65
|
-
require 'rgeo/active_record/
|
66
|
-
require 'rgeo/active_record/
|
78
|
+
require 'rgeo/active_record/version.rb'
|
79
|
+
require 'rgeo/active_record/spatial_expressions.rb'
|
80
|
+
require 'rgeo/active_record/arel_spatial_queries'
|
81
|
+
require 'rgeo/active_record/common_adapter_elements.rb'
|
82
|
+
require 'rgeo/active_record/ar_factory_settings'
|
@@ -37,10 +37,6 @@
|
|
37
37
|
require 'active_record'
|
38
38
|
|
39
39
|
|
40
|
-
# RGeo extensions to ActiveRecord are installed when one of the spatial
|
41
|
-
# connection adapters is needed. These modifications require ActiveRecord
|
42
|
-
# 3.0.3 or later.
|
43
|
-
|
44
40
|
module ActiveRecord
|
45
41
|
|
46
42
|
|
@@ -64,9 +60,6 @@ module ActiveRecord
|
|
64
60
|
class Base
|
65
61
|
|
66
62
|
|
67
|
-
self.attribute_types_cached_by_default << :geometry
|
68
|
-
|
69
|
-
|
70
63
|
class_attribute :rgeo_factory_generator, :instance_writer => false
|
71
64
|
self.rgeo_factory_generator = nil
|
72
65
|
|
@@ -110,37 +103,6 @@ module ActiveRecord
|
|
110
103
|
end
|
111
104
|
|
112
105
|
|
113
|
-
# :stopdoc:
|
114
|
-
alias_method :columns_without_rgeo_modification, :columns
|
115
|
-
def columns
|
116
|
-
unless defined?(@columns) && @columns
|
117
|
-
columns_without_rgeo_modification.each do |column_|
|
118
|
-
column_.set_ar_class(self) if column_.respond_to?(:set_ar_class)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
@columns
|
122
|
-
end
|
123
|
-
# :startdoc:
|
124
|
-
|
125
|
-
end
|
126
|
-
|
127
|
-
end
|
128
|
-
|
129
|
-
|
130
|
-
module ConnectionAdapters # :nodoc:
|
131
|
-
|
132
|
-
class TableDefinition # :nodoc:
|
133
|
-
|
134
|
-
::RGeo::ActiveRecord::GEOMETRY_TYPES.each do |type_|
|
135
|
-
method_ = <<-END_METHOD
|
136
|
-
def #{type_}(*args_)
|
137
|
-
opts_ = args_.extract_options!
|
138
|
-
args_.each{ |name_| column(name_, '#{type_}', opts_) }
|
139
|
-
end
|
140
|
-
END_METHOD
|
141
|
-
class_eval(method_, __FILE__, __LINE__-5)
|
142
|
-
end
|
143
|
-
|
144
106
|
end
|
145
107
|
|
146
108
|
end
|
@@ -0,0 +1,250 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Mysqlgeo adapter for ActiveRecord
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# Copyright 2010 Daniel Azuma
|
7
|
+
#
|
8
|
+
# All rights reserved.
|
9
|
+
#
|
10
|
+
# Redistribution and use in source and binary forms, with or without
|
11
|
+
# modification, are permitted provided that the following conditions are met:
|
12
|
+
#
|
13
|
+
# * Redistributions of source code must retain the above copyright notice,
|
14
|
+
# this list of conditions and the following disclaimer.
|
15
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer in the documentation
|
17
|
+
# and/or other materials provided with the distribution.
|
18
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
19
|
+
# contributors to this software, may be used to endorse or promote products
|
20
|
+
# derived from this software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
25
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
26
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
27
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
28
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
29
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
30
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
# -----------------------------------------------------------------------------
|
34
|
+
;
|
35
|
+
|
36
|
+
|
37
|
+
module RGeo
|
38
|
+
|
39
|
+
module ActiveRecord
|
40
|
+
|
41
|
+
|
42
|
+
# A set of common Arel visitor hacks for spatial ToSql visitors.
|
43
|
+
# Generally, a spatial ActiveRecord adapter should provide a custom
|
44
|
+
# ToSql Arel visitor that includes and customizes this module.
|
45
|
+
# See the existing spatial adapters (i.e. postgis, spatialite,
|
46
|
+
# mysqlspatial, and mysql2spatial) for usage examples.
|
47
|
+
|
48
|
+
module SpatialToSql
|
49
|
+
|
50
|
+
|
51
|
+
# Map a standard OGC SQL function name to the actual name used by
|
52
|
+
# a particular database. This method should take a name and
|
53
|
+
# return either the changed name or the original name.
|
54
|
+
|
55
|
+
def st_func(standard_name_)
|
56
|
+
standard_name_
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
# Visit the SpatialNamedFunction node. This operates similarly to
|
61
|
+
# the standard NamedFunction node, but it performs function name
|
62
|
+
# mapping for the database, and it also uses the type information
|
63
|
+
# in the node to determine when to cast string arguments to WKT,
|
64
|
+
|
65
|
+
def visit_RGeo_ActiveRecord_SpatialNamedFunction(node_)
|
66
|
+
name_ = st_func(node_.name)
|
67
|
+
exprs_ = []
|
68
|
+
node_.expressions.each_with_index do |expr_, index_|
|
69
|
+
exprs_ << (node_.spatial_argument?(index_) ? visit_in_spatial_context(expr_) : visit(expr_))
|
70
|
+
end
|
71
|
+
"#{name_}(#{node_.distinct ? 'DISTINCT ' : ''}#{exprs_.join(', ')})#{node_.alias ? " AS #{visit node_.alias}" : ''}"
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# Returns a true value if the given node is of spatial type-- that
|
76
|
+
# is, if it is a spatial literal or a reference to a spatial
|
77
|
+
# attribute.
|
78
|
+
|
79
|
+
def node_has_spatial_type?(node_)
|
80
|
+
case node_
|
81
|
+
when ::Arel::Attribute
|
82
|
+
@connection.instance_variable_set(:@_getting_columns, true)
|
83
|
+
begin
|
84
|
+
col_ = @engine.columns_hash[node_.name.to_s] unless @engine == ::ActiveRecord::Base
|
85
|
+
col_ && col_.respond_to?(:spatial?) && col_.spatial? ? true : false
|
86
|
+
ensure
|
87
|
+
@connection.instance_variable_set(:@_getting_columns, false)
|
88
|
+
end
|
89
|
+
when ::RGeo::ActiveRecord::SpatialNamedFunction
|
90
|
+
node_.spatial_result?
|
91
|
+
when ::RGeo::ActiveRecord::SpatialConstantNode, ::RGeo::Feature::Instance
|
92
|
+
true
|
93
|
+
else
|
94
|
+
false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
# Generates SQL for a spatial node.
|
100
|
+
# The node must be a string (in which case it is treated as WKT),
|
101
|
+
# an RGeo feature, or a spatial attribute.
|
102
|
+
|
103
|
+
def visit_in_spatial_context(node_)
|
104
|
+
case node_
|
105
|
+
when ::String
|
106
|
+
"#{st_func('ST_WKTToSQL')}(#{visit_String(node_)})"
|
107
|
+
when ::RGeo::Feature::Instance
|
108
|
+
visit_RGeo_Feature_Instance(node_)
|
109
|
+
else
|
110
|
+
visit(node_)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
def _check_equality_for_rgeo(node_, negate_) # :nodoc:
|
116
|
+
left_ = node_.left
|
117
|
+
right_ = node_.right
|
118
|
+
if !@connection.instance_variable_get(:@_getting_columns) && !right_.nil? && (node_has_spatial_type?(left_) || node_has_spatial_type?(right_))
|
119
|
+
"#{negate_ ? 'NOT ' : ''}#{st_func('ST_Equals')}(#{visit_in_spatial_context(left_)}, #{visit_in_spatial_context(right_)})"
|
120
|
+
else
|
121
|
+
false
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
# Override equality nodes to use the ST_Equals function if at least
|
127
|
+
# one of the operands is a spatial node.
|
128
|
+
|
129
|
+
def visit_Arel_Nodes_Equality(node_)
|
130
|
+
_check_equality_for_rgeo(node_, false) || super
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
# Override equality nodes to use the ST_Equals function if at least
|
135
|
+
# one of the operands is a spatial node.
|
136
|
+
|
137
|
+
def visit_Arel_Nodes_NotEqual(node_)
|
138
|
+
_check_equality_for_rgeo(node_, true) || super
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
# :stopdoc:
|
150
|
+
|
151
|
+
|
152
|
+
# This node wraps an RGeo feature and gives it spatial expression
|
153
|
+
# constructors.
|
154
|
+
|
155
|
+
module RGeo
|
156
|
+
module ActiveRecord
|
157
|
+
|
158
|
+
class SpatialConstantNode
|
159
|
+
|
160
|
+
include ::RGeo::ActiveRecord::SpatialExpressions
|
161
|
+
|
162
|
+
def initialize(delegate_)
|
163
|
+
@delegate = delegate_
|
164
|
+
end
|
165
|
+
|
166
|
+
attr_reader :delegate
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
# Make sure the standard Arel visitors can handle RGeo feature objects
|
175
|
+
# by default.
|
176
|
+
|
177
|
+
module Arel
|
178
|
+
module Visitors
|
179
|
+
class Visitor
|
180
|
+
def visit_RGeo_ActiveRecord_SpatialConstantNode(node_)
|
181
|
+
if respond_to?(:visit_in_spatial_context)
|
182
|
+
visit_in_spatial_context(node_.delegate)
|
183
|
+
else
|
184
|
+
visit(node_.delegate)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
class Dot
|
189
|
+
alias :visit_RGeo_Feature_Instance :visit_String
|
190
|
+
end
|
191
|
+
class DepthFirst
|
192
|
+
alias :visit_RGeo_Feature_Instance :terminal
|
193
|
+
end
|
194
|
+
class ToSql
|
195
|
+
alias :visit_RGeo_Feature_Instance :visit_String
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
# Add tools to build spatial structures in the AST.
|
202
|
+
# This stuff requires Arel 2.1 or later.
|
203
|
+
|
204
|
+
if defined?(::Arel::Nodes::NamedFunction)
|
205
|
+
|
206
|
+
# Allow chaining of predications from named functions
|
207
|
+
# (Hack because Arel doesn't do this but should.)
|
208
|
+
::Arel::Nodes::NamedFunction.class_eval do
|
209
|
+
include ::Arel::Predications unless include?(::Arel::Predications)
|
210
|
+
end
|
211
|
+
|
212
|
+
# Allow chaining of spatial expressions from attributes
|
213
|
+
::Arel::Attribute.class_eval do
|
214
|
+
include ::RGeo::ActiveRecord::SpatialExpressions
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
# A NamedFunction subclass that keeps track of the spatial-ness of
|
219
|
+
# the arguments and return values, so that it can provide context to
|
220
|
+
# visitors that want to interpret syntax differently when dealing with
|
221
|
+
# spatial elements.
|
222
|
+
|
223
|
+
class ::RGeo::ActiveRecord::SpatialNamedFunction < ::Arel::Nodes::NamedFunction
|
224
|
+
|
225
|
+
include ::RGeo::ActiveRecord::SpatialExpressions
|
226
|
+
|
227
|
+
def initialize(name_, expr_, spatial_flags_=[], aliaz_=nil)
|
228
|
+
super(name_, expr_, aliaz_)
|
229
|
+
@spatial_flags = spatial_flags_
|
230
|
+
end
|
231
|
+
|
232
|
+
def spatial_result?
|
233
|
+
@spatial_flags.first
|
234
|
+
end
|
235
|
+
|
236
|
+
def spatial_argument?(index_)
|
237
|
+
@spatial_flags[index_+1]
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
else
|
243
|
+
|
244
|
+
# A dummy SpatialNamedFunction for pre-2.1 versions of Arel.
|
245
|
+
class ::RGeo::ActiveRecord::SpatialNamedFunction; end
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
|
250
|
+
# :startdoc:
|
@@ -0,0 +1,226 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Common tools for spatial adapters for ActiveRecord
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# Copyright 2010 Daniel Azuma
|
7
|
+
#
|
8
|
+
# All rights reserved.
|
9
|
+
#
|
10
|
+
# Redistribution and use in source and binary forms, with or without
|
11
|
+
# modification, are permitted provided that the following conditions are met:
|
12
|
+
#
|
13
|
+
# * Redistributions of source code must retain the above copyright notice,
|
14
|
+
# this list of conditions and the following disclaimer.
|
15
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer in the documentation
|
17
|
+
# and/or other materials provided with the distribution.
|
18
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
19
|
+
# contributors to this software, may be used to endorse or promote products
|
20
|
+
# derived from this software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
25
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
26
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
27
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
28
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
29
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
30
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
# -----------------------------------------------------------------------------
|
34
|
+
;
|
35
|
+
|
36
|
+
|
37
|
+
module RGeo
|
38
|
+
|
39
|
+
module ActiveRecord
|
40
|
+
|
41
|
+
|
42
|
+
# Some default column constructors specifications for most spatial
|
43
|
+
# databases. Individual adapters may add to or override this list.
|
44
|
+
|
45
|
+
DEFAULT_SPATIAL_COLUMN_CONSTRUCTORS = {
|
46
|
+
:spatial => {:type => 'geometry'},
|
47
|
+
:geometry => {},
|
48
|
+
:point => {},
|
49
|
+
:line_string => {},
|
50
|
+
:polygon => {},
|
51
|
+
:geometry_collection => {},
|
52
|
+
:multi_line_string => {},
|
53
|
+
:multi_point => {},
|
54
|
+
:multi_polygon => {},
|
55
|
+
}.freeze
|
56
|
+
|
57
|
+
|
58
|
+
# The default factory generator for ActiveRecord::Base.
|
59
|
+
|
60
|
+
DEFAULT_FACTORY_GENERATOR = ::Proc.new do |config_|
|
61
|
+
if config_.delete(:geographic)
|
62
|
+
::RGeo::Geographic.spherical_factory(config_)
|
63
|
+
else
|
64
|
+
::RGeo::Cartesian.preferred_factory(config_)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# Index definition struct with a spatial flag field.
|
70
|
+
|
71
|
+
class SpatialIndexDefinition < ::Struct.new(:table, :name, :unique, :columns, :lengths, :spatial)
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# Returns a feature type module given a string type.
|
76
|
+
|
77
|
+
def self.geometric_type_from_name(name_)
|
78
|
+
case name_.to_s
|
79
|
+
when /^geometry/i then ::RGeo::Feature::Geometry
|
80
|
+
when /^point/i then ::RGeo::Feature::Point
|
81
|
+
when /^linestring/i then ::RGeo::Feature::LineString
|
82
|
+
when /^polygon/i then ::RGeo::Feature::Polygon
|
83
|
+
when /^geometrycollection/i then ::RGeo::Feature::GeometryCollection
|
84
|
+
when /^multipoint/i then ::RGeo::Feature::MultiPoint
|
85
|
+
when /^multilinestring/i then ::RGeo::Feature::MultiLineString
|
86
|
+
when /^multipolygon/i then ::RGeo::Feature::MultiPolygon
|
87
|
+
else nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# :stopdoc:
|
98
|
+
|
99
|
+
|
100
|
+
# Make sure a few things are autoloaded before we modify them.
|
101
|
+
::Arel::Attributes
|
102
|
+
::ActiveRecord::ConnectionAdapters::AbstractAdapter
|
103
|
+
::ActiveRecord::ConnectionAdapters::TableDefinition
|
104
|
+
::ActiveRecord::ConnectionAdapters::Table
|
105
|
+
::ActiveRecord::Base
|
106
|
+
::ActiveRecord::SchemaDumper
|
107
|
+
|
108
|
+
|
109
|
+
# Hack Arel Attributes dispatcher to recognize geometry columns.
|
110
|
+
# This is deprecated but necessary to support legacy Arel versions.
|
111
|
+
|
112
|
+
module Arel
|
113
|
+
module Attributes
|
114
|
+
class << self
|
115
|
+
if method_defined?(:for)
|
116
|
+
alias_method :for_without_rgeo_modification, :for
|
117
|
+
def for(column_)
|
118
|
+
column_.type == :spatial ? Attribute : for_without_rgeo_modification(column_)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
# Provide methods for each geometric subtype during table definitions.
|
127
|
+
|
128
|
+
module ActiveRecord
|
129
|
+
module ConnectionAdapters
|
130
|
+
class TableDefinition
|
131
|
+
|
132
|
+
alias_method :method_missing_without_rgeo_modification, :method_missing
|
133
|
+
def method_missing(method_name_, *args_, &block_)
|
134
|
+
if @base.respond_to?(:spatial_column_constructor) && (info_ = @base.spatial_column_constructor(method_name_))
|
135
|
+
type_ = (info_.delete(:type) || method_name_).to_s
|
136
|
+
opts_ = args_.extract_options!.merge(info_)
|
137
|
+
args_.each do |name_|
|
138
|
+
column(name_, type_, opts_)
|
139
|
+
end
|
140
|
+
else
|
141
|
+
method_missing_without_rgeo_modification(method_name_, *args_, &block_)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
# Provide methods for each geometric subtype during table changes.
|
151
|
+
|
152
|
+
module ActiveRecord
|
153
|
+
module ConnectionAdapters
|
154
|
+
class Table
|
155
|
+
|
156
|
+
alias_method :method_missing_without_rgeo_modification, :method_missing
|
157
|
+
def method_missing(method_name_, *args_, &block_)
|
158
|
+
if @base.respond_to?(:spatial_column_constructor) && (info_ = @base.spatial_column_constructor(method_name_))
|
159
|
+
type_ = (info_.delete(:type) || method_name_).to_s
|
160
|
+
opts_ = args_.extract_options!.merge(info_)
|
161
|
+
args_.each do |name_|
|
162
|
+
@base.add_column(@table_name, name_, type_, opts_)
|
163
|
+
end
|
164
|
+
else
|
165
|
+
method_missing_without_rgeo_modification(method_name_, *args_, &block_)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
# When creating column objects, cause the enclosing ActiveRecord class
|
175
|
+
# to be set on any column that recognizes it. This is commonly used by
|
176
|
+
# spatial column subclasses.
|
177
|
+
|
178
|
+
module ActiveRecord
|
179
|
+
class Base
|
180
|
+
class << self
|
181
|
+
alias_method :columns_without_rgeo_modification, :columns
|
182
|
+
def columns
|
183
|
+
unless defined?(@columns) && @columns
|
184
|
+
columns_without_rgeo_modification.each do |column_|
|
185
|
+
column_.set_ar_class(self) if column_.respond_to?(:set_ar_class)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
@columns
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
# Hack schema dumper to output spatial index flag
|
196
|
+
|
197
|
+
module ActiveRecord
|
198
|
+
class SchemaDumper
|
199
|
+
private
|
200
|
+
def indexes(table_, stream_)
|
201
|
+
if (indexes_ = @connection.indexes(table_)).any?
|
202
|
+
add_index_statements_ = indexes_.map do |index_|
|
203
|
+
statement_parts_ = [ ('add_index ' + index_.table.inspect) ]
|
204
|
+
statement_parts_ << index_.columns.inspect
|
205
|
+
statement_parts_ << (':name => ' + index_.name.inspect)
|
206
|
+
statement_parts_ << ':unique => true' if index_.unique
|
207
|
+
statement_parts_ << ':spatial => true' if index_.respond_to?(:spatial) && index_.spatial
|
208
|
+
index_lengths_ = index_.lengths.compact if index_.lengths.is_a?(::Array)
|
209
|
+
statement_parts_ << (':length => ' + ::Hash[*index_.columns.zip(index_.lengths).flatten].inspect) if index_lengths_.present?
|
210
|
+
' ' + statement_parts_.join(', ')
|
211
|
+
end
|
212
|
+
stream_.puts add_index_statements_.sort.join("\n")
|
213
|
+
stream_.puts
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
|
220
|
+
# Tell ActiveRecord to cache spatial attribute values so they don't get
|
221
|
+
# re-parsed on every access.
|
222
|
+
|
223
|
+
::ActiveRecord::Base.attribute_types_cached_by_default << :spatial
|
224
|
+
|
225
|
+
|
226
|
+
# :startdoc:
|
@@ -0,0 +1,314 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Common tools for spatial adapters for ActiveRecord
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# Copyright 2010 Daniel Azuma
|
7
|
+
#
|
8
|
+
# All rights reserved.
|
9
|
+
#
|
10
|
+
# Redistribution and use in source and binary forms, with or without
|
11
|
+
# modification, are permitted provided that the following conditions are met:
|
12
|
+
#
|
13
|
+
# * Redistributions of source code must retain the above copyright notice,
|
14
|
+
# this list of conditions and the following disclaimer.
|
15
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer in the documentation
|
17
|
+
# and/or other materials provided with the distribution.
|
18
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
19
|
+
# contributors to this software, may be used to endorse or promote products
|
20
|
+
# derived from this software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
25
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
26
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
27
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
28
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
29
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
30
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
# -----------------------------------------------------------------------------
|
34
|
+
;
|
35
|
+
|
36
|
+
|
37
|
+
module RGeo
|
38
|
+
|
39
|
+
module ActiveRecord
|
40
|
+
|
41
|
+
|
42
|
+
# Returns true if spatial expressions (i.e. the methods in the
|
43
|
+
# SpatialExpressions module) are supported. Generally, this is true
|
44
|
+
# if Arel is at version 2.1 or later.
|
45
|
+
|
46
|
+
def self.spatial_expressions_supported?
|
47
|
+
defined?(::Arel::Nodes::NamedFunction)
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# A set of spatial expression builders.
|
52
|
+
# These methods can be chained off other spatial expressions to form
|
53
|
+
# complex expressions.
|
54
|
+
#
|
55
|
+
# These functions require Arel 2.1 or later.
|
56
|
+
|
57
|
+
module SpatialExpressions
|
58
|
+
|
59
|
+
|
60
|
+
#--
|
61
|
+
# Generic functions
|
62
|
+
#++
|
63
|
+
|
64
|
+
def st_function(function_, *args_)
|
65
|
+
spatial_info_ = args_.last.is_a?(::Array) ? args_.pop : []
|
66
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new(function_, [self] + args_, spatial_info_)
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
#--
|
71
|
+
# Geometry functions
|
72
|
+
#++
|
73
|
+
|
74
|
+
def st_dimension
|
75
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Dimension', [self], [false, true])
|
76
|
+
end
|
77
|
+
|
78
|
+
def st_geometrytype
|
79
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_GeometryType', [self], [false, true])
|
80
|
+
end
|
81
|
+
|
82
|
+
def st_astext
|
83
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_AsText', [self], [false, true])
|
84
|
+
end
|
85
|
+
|
86
|
+
def st_asbinary
|
87
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_AsBinary', [self], [false, true])
|
88
|
+
end
|
89
|
+
|
90
|
+
def st_srid
|
91
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_SRID', [self], [false, true])
|
92
|
+
end
|
93
|
+
|
94
|
+
def st_isempty
|
95
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_IsEmpty', [self], [false, true])
|
96
|
+
end
|
97
|
+
|
98
|
+
def st_issimple
|
99
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_IsSimple', [self], [false, true])
|
100
|
+
end
|
101
|
+
|
102
|
+
def st_boundary
|
103
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Boundary', [self], [true, true])
|
104
|
+
end
|
105
|
+
|
106
|
+
def st_envelope
|
107
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Envelope', [self], [true, true])
|
108
|
+
end
|
109
|
+
|
110
|
+
def st_equals(rhs_)
|
111
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Equals', [self, rhs_], [false, true, true])
|
112
|
+
end
|
113
|
+
|
114
|
+
def st_disjoint(rhs_)
|
115
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Disjoint', [self, rhs_], [false, true, true])
|
116
|
+
end
|
117
|
+
|
118
|
+
def st_intersects(rhs_)
|
119
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Intersects', [self, rhs_], [false, true, true])
|
120
|
+
end
|
121
|
+
|
122
|
+
def st_touches(rhs_)
|
123
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Touches', [self, rhs_], [false, true, true])
|
124
|
+
end
|
125
|
+
|
126
|
+
def st_crosses(rhs_)
|
127
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Crosses', [self, rhs_], [false, true, true])
|
128
|
+
end
|
129
|
+
|
130
|
+
def st_within(rhs_)
|
131
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Within', [self, rhs_], [false, true, true])
|
132
|
+
end
|
133
|
+
|
134
|
+
def st_contains(rhs_)
|
135
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Contains', [self, rhs_], [false, true, true])
|
136
|
+
end
|
137
|
+
|
138
|
+
def st_overlaps(rhs_)
|
139
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Overlaps', [self, rhs_], [false, true, true])
|
140
|
+
end
|
141
|
+
|
142
|
+
def st_relate(rhs_, matrix_=nil)
|
143
|
+
args_ = [self, rhs_]
|
144
|
+
args_ << matrix.to_s if matrix_
|
145
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Relate', args_, [false, true, true, false])
|
146
|
+
end
|
147
|
+
|
148
|
+
def st_distance(rhs_, units_=nil)
|
149
|
+
args_ = [self, rhs_]
|
150
|
+
args_ << units.to_s if units_
|
151
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Distance', args_, [false, true, true, false])
|
152
|
+
end
|
153
|
+
|
154
|
+
def st_intersection(rhs_)
|
155
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Intersection', [self, rhs_], [true, true, true])
|
156
|
+
end
|
157
|
+
|
158
|
+
def st_difference(rhs_)
|
159
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Difference', [self, rhs_], [true, true, true])
|
160
|
+
end
|
161
|
+
|
162
|
+
def st_union(rhs_)
|
163
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Union', [self, rhs_], [true, true, true])
|
164
|
+
end
|
165
|
+
|
166
|
+
def st_symdifference(rhs_)
|
167
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_SymDifference', [self, rhs_], [true, true, true])
|
168
|
+
end
|
169
|
+
|
170
|
+
def st_buffer(distance_, units_=nil)
|
171
|
+
args_ = [self, distance_.to_f]
|
172
|
+
args_ << units.to_s if units_
|
173
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Buffer', args_, [true, true, false])
|
174
|
+
end
|
175
|
+
|
176
|
+
def st_convexhull
|
177
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_ConvexHull', [self], [true, true])
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
#--
|
182
|
+
# Point functions
|
183
|
+
#++
|
184
|
+
|
185
|
+
def st_x
|
186
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_X', [self], [false, true])
|
187
|
+
end
|
188
|
+
|
189
|
+
def st_y
|
190
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Y', [self], [false, true])
|
191
|
+
end
|
192
|
+
|
193
|
+
def st_z
|
194
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Z', [self], [false, true])
|
195
|
+
end
|
196
|
+
|
197
|
+
def st_m
|
198
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_M', [self], [false, true])
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
#--
|
203
|
+
# Curve functions
|
204
|
+
#++
|
205
|
+
|
206
|
+
def st_startpoint
|
207
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_StartPoint', [self], [true, true])
|
208
|
+
end
|
209
|
+
|
210
|
+
def st_endpoint
|
211
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_EndPoint', [self], [true, true])
|
212
|
+
end
|
213
|
+
|
214
|
+
def st_isclosed
|
215
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_IsClosed', [self], [false, true])
|
216
|
+
end
|
217
|
+
|
218
|
+
def st_isring
|
219
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_IsRing', [self], [false, true])
|
220
|
+
end
|
221
|
+
|
222
|
+
def st_length(units_=nil)
|
223
|
+
args_ = [self]
|
224
|
+
args_ << units.to_s if units_
|
225
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Length', args_, [false, true, false])
|
226
|
+
end
|
227
|
+
|
228
|
+
|
229
|
+
#--
|
230
|
+
# LineString functions
|
231
|
+
#++
|
232
|
+
|
233
|
+
def st_numpoints
|
234
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_NumPoints', [self], [false, true])
|
235
|
+
end
|
236
|
+
|
237
|
+
def st_pointn(n_)
|
238
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_PointN', [self, n_.to_i], [true, true, false])
|
239
|
+
end
|
240
|
+
|
241
|
+
|
242
|
+
#--
|
243
|
+
# Surface functions
|
244
|
+
#++
|
245
|
+
|
246
|
+
def st_area(units_=nil)
|
247
|
+
args_ = [self]
|
248
|
+
args_ << units.to_s if units_
|
249
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_StartPoint', args_, [false, true, false])
|
250
|
+
end
|
251
|
+
|
252
|
+
def st_centroid
|
253
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_Centroid', [self], [true, true])
|
254
|
+
end
|
255
|
+
|
256
|
+
def st_pointonsurface
|
257
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_PointOnSurface', [self], [true, true])
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
#--
|
262
|
+
# Polygon functions
|
263
|
+
#++
|
264
|
+
|
265
|
+
def st_exteriorring
|
266
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_ExteriorRing', [self], [true, true])
|
267
|
+
end
|
268
|
+
|
269
|
+
def st_numinteriorrings
|
270
|
+
# Note: the name difference is intentional. The standard
|
271
|
+
# names this function incorrectly.
|
272
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_NumInteriorRing', [self], [false, true])
|
273
|
+
end
|
274
|
+
|
275
|
+
def st_interiorringn(n_)
|
276
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_InteriorRingN', [self, n_.to_i], [true, true, false])
|
277
|
+
end
|
278
|
+
|
279
|
+
|
280
|
+
#--
|
281
|
+
# GeometryCollection functions
|
282
|
+
#++
|
283
|
+
|
284
|
+
def st_numgeometries
|
285
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_NumGeometries', [self], [false, true])
|
286
|
+
end
|
287
|
+
|
288
|
+
def st_geometryn(n_)
|
289
|
+
::RGeo::ActiveRecord::SpatialNamedFunction.new('ST_GeometryN', [self, n_.to_i], [true, true, false])
|
290
|
+
end
|
291
|
+
|
292
|
+
|
293
|
+
end
|
294
|
+
|
295
|
+
|
296
|
+
end
|
297
|
+
|
298
|
+
end
|
299
|
+
|
300
|
+
|
301
|
+
module Arel
|
302
|
+
|
303
|
+
# Create a spatial constant node.
|
304
|
+
# This node wraps a spatial value (such as an RGeo feature or a text
|
305
|
+
# string in WKT format). It supports chaining with the functions
|
306
|
+
# defined by RGeo::ActiveRecord::SpatialExpressions.
|
307
|
+
#
|
308
|
+
# Requires Arel 2.1 or later.
|
309
|
+
|
310
|
+
def self.spatial(arg_)
|
311
|
+
::RGeo::ActiveRecord::SpatialConstantNode.new(arg_)
|
312
|
+
end
|
313
|
+
|
314
|
+
end
|
@@ -53,10 +53,15 @@ module RGeo
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def call(task_)
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
@
|
56
|
+
env_ = @env || ::Rails.env || 'development'
|
57
|
+
config_ = ::ActiveRecord::Base.configurations[env_]
|
58
|
+
if config_
|
59
|
+
if @pattern === config_['adapter']
|
60
|
+
task_.actions.delete_if{ |a_| a_ != self }
|
61
|
+
@proc.call(config_)
|
62
|
+
end
|
63
|
+
else
|
64
|
+
puts "WARNING: Could not find environment #{env_.inspect} in your database.yml"
|
60
65
|
end
|
61
66
|
end
|
62
67
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# -----------------------------------------------------------------------------
|
2
2
|
#
|
3
|
-
#
|
3
|
+
# Version of rgeo-activerecord
|
4
4
|
#
|
5
5
|
# -----------------------------------------------------------------------------
|
6
6
|
# Copyright 2010 Daniel Azuma
|
@@ -34,44 +34,22 @@
|
|
34
34
|
;
|
35
35
|
|
36
36
|
|
37
|
-
|
37
|
+
begin
|
38
|
+
require 'versionomy'
|
39
|
+
rescue ::LoadError
|
40
|
+
end
|
38
41
|
|
39
42
|
|
40
|
-
|
41
|
-
# support geometry values in the AST.
|
42
|
-
module Arel
|
43
|
-
|
44
|
-
# Hack Attributes dispatcher to recognize geometry columns.
|
45
|
-
# This is deprecated but necessary to support legacy Arel versions.
|
46
|
-
module Attributes # :nodoc:
|
47
|
-
class << self
|
48
|
-
if method_defined?(:for)
|
49
|
-
alias_method :for_without_geometry, :for
|
50
|
-
def for(column_)
|
51
|
-
column_.type == :geometry ? Attribute : for_without_geometry(column_)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
43
|
+
module RGeo
|
56
44
|
|
57
|
-
|
58
|
-
# the AST.
|
59
|
-
module Visitors
|
60
|
-
|
61
|
-
# RGeo adds visit_RGeo_Feature_Instance to the Dot visitor.
|
62
|
-
class Dot
|
63
|
-
alias :visit_RGeo_Feature_Instance :visit_String
|
64
|
-
end
|
45
|
+
module ActiveRecord
|
65
46
|
|
66
|
-
#
|
67
|
-
|
68
|
-
alias :visit_RGeo_Feature_Instance :terminal
|
69
|
-
end
|
47
|
+
# Current version of RGeo::ActiveRecord as a frozen string
|
48
|
+
VERSION_STRING = ::File.read(::File.dirname(__FILE__)+'/../../../Version').strip.freeze
|
70
49
|
|
71
|
-
# RGeo
|
72
|
-
|
73
|
-
|
74
|
-
end
|
50
|
+
# Current version of RGeo::ActiveRecord as a Versionomy object, if the
|
51
|
+
# Versionomy gem is available; otherwise equal to VERSION_STRING.
|
52
|
+
VERSION = defined?(::Versionomy) ? ::Versionomy.parse(VERSION_STRING) : VERSION_STRING
|
75
53
|
|
76
54
|
end
|
77
55
|
|
data/test/tc_basic.rb
CHANGED
@@ -45,6 +45,11 @@ module RGeo
|
|
45
45
|
class TestBasic < ::Test::Unit::TestCase # :nodoc:
|
46
46
|
|
47
47
|
|
48
|
+
def test_has_version
|
49
|
+
assert_not_nil(::RGeo::ActiveRecord::VERSION)
|
50
|
+
end
|
51
|
+
|
52
|
+
|
48
53
|
def test_default_factory_generator
|
49
54
|
::ActiveRecord::Base.rgeo_factory_generator = nil
|
50
55
|
factory_ = ::ActiveRecord::Base.rgeo_factory_for_column(:hello).call(:has_z_coordinate => true, :srid => 4326)
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 3
|
8
|
+
- 0
|
9
|
+
version: 0.3.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Daniel Azuma
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-01-
|
17
|
+
date: 2011-01-26 00:00:00 -08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -73,10 +73,12 @@ extra_rdoc_files:
|
|
73
73
|
- README.rdoc
|
74
74
|
files:
|
75
75
|
- lib/rgeo/active_record/adapter_test_helper.rb
|
76
|
-
- lib/rgeo/active_record/
|
77
|
-
- lib/rgeo/active_record/
|
78
|
-
- lib/rgeo/active_record/
|
76
|
+
- lib/rgeo/active_record/ar_factory_settings.rb
|
77
|
+
- lib/rgeo/active_record/arel_spatial_queries.rb
|
78
|
+
- lib/rgeo/active_record/common_adapter_elements.rb
|
79
|
+
- lib/rgeo/active_record/spatial_expressions.rb
|
79
80
|
- lib/rgeo/active_record/task_hacker.rb
|
81
|
+
- lib/rgeo/active_record/version.rb
|
80
82
|
- lib/rgeo/active_record.rb
|
81
83
|
- History.rdoc
|
82
84
|
- README.rdoc
|
@@ -1,148 +0,0 @@
|
|
1
|
-
# -----------------------------------------------------------------------------
|
2
|
-
#
|
3
|
-
# Common tools for spatial adapters for ActiveRecord
|
4
|
-
#
|
5
|
-
# -----------------------------------------------------------------------------
|
6
|
-
# Copyright 2010 Daniel Azuma
|
7
|
-
#
|
8
|
-
# All rights reserved.
|
9
|
-
#
|
10
|
-
# Redistribution and use in source and binary forms, with or without
|
11
|
-
# modification, are permitted provided that the following conditions are met:
|
12
|
-
#
|
13
|
-
# * Redistributions of source code must retain the above copyright notice,
|
14
|
-
# this list of conditions and the following disclaimer.
|
15
|
-
# * Redistributions in binary form must reproduce the above copyright notice,
|
16
|
-
# this list of conditions and the following disclaimer in the documentation
|
17
|
-
# and/or other materials provided with the distribution.
|
18
|
-
# * Neither the name of the copyright holder, nor the names of any other
|
19
|
-
# contributors to this software, may be used to endorse or promote products
|
20
|
-
# derived from this software without specific prior written permission.
|
21
|
-
#
|
22
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
-
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
-
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
25
|
-
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
26
|
-
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
27
|
-
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
28
|
-
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
29
|
-
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
30
|
-
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
31
|
-
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
32
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
33
|
-
# -----------------------------------------------------------------------------
|
34
|
-
;
|
35
|
-
|
36
|
-
|
37
|
-
module RGeo
|
38
|
-
|
39
|
-
module ActiveRecord
|
40
|
-
|
41
|
-
|
42
|
-
# Additional column types for geometries.
|
43
|
-
GEOMETRY_TYPES = [:geometry, :point, :line_string, :polygon, :geometry_collection, :multi_line_string, :multi_point, :multi_polygon].freeze
|
44
|
-
|
45
|
-
# The default factory generator for ActiveRecord::Base.
|
46
|
-
DEFAULT_FACTORY_GENERATOR = ::Proc.new do |config_|
|
47
|
-
if config_.delete(:geographic)
|
48
|
-
::RGeo::Geographic.spherical_factory(config_)
|
49
|
-
else
|
50
|
-
::RGeo::Cartesian.preferred_factory(config_)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
|
55
|
-
# A set of common Arel visitor hacks for spatial ToSql visitors.
|
56
|
-
|
57
|
-
module SpatialToSql
|
58
|
-
|
59
|
-
# Map a standard OGC SQL function name to the actual name used by
|
60
|
-
# a particular database.
|
61
|
-
def st_func(standard_name_)
|
62
|
-
standard_name_
|
63
|
-
end
|
64
|
-
|
65
|
-
# Returns true if the given node is of spatial type-- that is, if
|
66
|
-
# it is a spatial literal or a reference to a spatial attribute.
|
67
|
-
def node_has_spatial_type?(node_)
|
68
|
-
case node_
|
69
|
-
when ::Arel::Attribute
|
70
|
-
@connection.instance_variable_set(:@_getting_columns, true)
|
71
|
-
begin
|
72
|
-
col_ = @engine.columns_hash[node_.name.to_s] unless @engine == ::ActiveRecord::Base
|
73
|
-
col_ && col_.respond_to?(:spatial?) && col_.spatial?
|
74
|
-
ensure
|
75
|
-
@connection.instance_variable_set(:@_getting_columns, false)
|
76
|
-
end
|
77
|
-
when ::RGeo::Feature::Instance
|
78
|
-
true
|
79
|
-
else
|
80
|
-
false
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
# Generates SQL for a spatial node.
|
85
|
-
def visit_spatial(node_)
|
86
|
-
case node_
|
87
|
-
when ::String
|
88
|
-
"#{st_func('ST_WKTToSQL')}(#{visit_String(node_)})"
|
89
|
-
when ::RGeo::Feature::Instance
|
90
|
-
visit_RGeo_Feature_Instance(node_)
|
91
|
-
else
|
92
|
-
visit(node_)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def visit_Arel_Nodes_Equality(node_) # :nodoc:
|
97
|
-
right_ = node_.right
|
98
|
-
left_ = node_.left
|
99
|
-
if !@connection.instance_variable_get(:@_getting_columns) && (node_has_spatial_type?(right_) || node_has_spatial_type?(left_))
|
100
|
-
"#{st_func('ST_Equals')}(#{visit_spatial(left_)}, #{visit_spatial(right_)})"
|
101
|
-
else
|
102
|
-
super
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def visit_Arel_Nodes_NotEqual(node_) # :nodoc:
|
107
|
-
right_ = node_.right
|
108
|
-
left_ = node_.left
|
109
|
-
if !@connection.instance_variable_get(:@_getting_columns) && (node_has_spatial_type?(right_) || node_has_spatial_type?(left_))
|
110
|
-
"NOT #{st_func('ST_Equals')}(#{visit_spatial(left_)}, #{visit_spatial(right_)})"
|
111
|
-
else
|
112
|
-
super
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
end
|
117
|
-
|
118
|
-
|
119
|
-
# Index definition struct with a spatial flag field.
|
120
|
-
|
121
|
-
class SpatialIndexDefinition < ::Struct.new(:table, :name, :unique, :columns, :lengths, :spatial)
|
122
|
-
end
|
123
|
-
|
124
|
-
|
125
|
-
class << self
|
126
|
-
|
127
|
-
|
128
|
-
# Returns a feature type module given a string type.
|
129
|
-
|
130
|
-
def geometric_type_from_name(name_)
|
131
|
-
case name_.downcase
|
132
|
-
when 'geometry' then ::RGeo::Feature::Geometry
|
133
|
-
when 'point' then ::RGeo::Feature::Point
|
134
|
-
when 'linestring' then ::RGeo::Feature::LineString
|
135
|
-
when 'polygon' then ::RGeo::Feature::Polygon
|
136
|
-
when 'geometrycollection' then ::RGeo::Feature::GeometryCollection
|
137
|
-
when 'multipoint' then ::RGeo::Feature::MultiPoint
|
138
|
-
when 'multilinestring' then ::RGeo::Feature::MultiLineString
|
139
|
-
when 'multipolygon' then ::RGeo::Feature::MultiPolygon
|
140
|
-
else nil
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
end
|
145
|
-
|
146
|
-
end
|
147
|
-
|
148
|
-
end
|