rgeo-activerecord 0.2.4 → 0.3.0
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.
- 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
|