rgeo 0.1.16 → 0.1.17

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,38 @@
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
+ require 'rgeo/active_record/arel_modifications'
38
+ require 'rgeo/active_record/base_modifications'
@@ -0,0 +1,187 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # MysqlSpatial adapter common tools 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
+ require 'rgeo/features'
38
+ require 'rgeo/cartesian'
39
+ require 'rgeo/wkrep'
40
+ require 'rgeo/active_record/common'
41
+
42
+
43
+ module RGeo
44
+
45
+ module ActiveRecord
46
+
47
+
48
+ module MysqlCommon
49
+
50
+
51
+ module AdapterMethods # :nodoc:
52
+
53
+
54
+ def quote(value_, column_=nil)
55
+ if ::RGeo::Features::Geometry.check_type(value_)
56
+ "GeomFromWKB(0x#{::RGeo::WKRep::WKBGenerator.new(:hex_format => true).generate(value_)},#{value_.srid})"
57
+ else
58
+ super
59
+ end
60
+ end
61
+
62
+
63
+ def add_index(table_name_, column_name_, options_={})
64
+ if options_[:spatial]
65
+ index_name_ = index_name(table_name_, :column => Array(column_name_))
66
+ if ::Hash === options_
67
+ index_name_ = options_[:name] || index_name_
68
+ end
69
+ execute "CREATE SPATIAL INDEX #{index_name_} ON #{table_name_} (#{Array(column_name_).join(", ")})"
70
+ else
71
+ super
72
+ end
73
+ end
74
+
75
+
76
+ end
77
+
78
+
79
+ class IndexDefinition < ::ActiveRecord::ConnectionAdapters::IndexDefinition # :nodoc:
80
+
81
+ attr_accessor :spatial
82
+
83
+ end
84
+
85
+
86
+ module ColumnMethods # :nodoc:
87
+
88
+
89
+ def initialize(name_, default_, sql_type_=nil, null_=true)
90
+ super(name_, default_,sql_type_, null_)
91
+ @geometric_type = extract_geometric_type(sql_type_)
92
+ @ar_class = nil
93
+ end
94
+
95
+
96
+ attr_writer :ar_class
97
+
98
+ attr_reader :geometric_type
99
+
100
+
101
+ def geometry?
102
+ type == :geometry
103
+ end
104
+
105
+
106
+ def klass
107
+ type == :geometry ? ::RGeo::Features::Geometry : super
108
+ end
109
+
110
+
111
+ def type_cast(value_)
112
+ self.geometry? ? ColumnMethods.string_to_geometry(value_, @ar_class) : super
113
+ end
114
+
115
+
116
+ def type_cast_code(var_name_)
117
+ self.geometry? ? "::RGeo::ActiveRecord::MysqlCommon::ColumnMethods.string_to_geometry(#{var_name_}, self.class)" : super
118
+ end
119
+
120
+
121
+ private
122
+
123
+ def extract_geometric_type(sql_type_)
124
+ case sql_type_
125
+ when /^geometry$/i then ::RGeo::Features::Geometry
126
+ when /^point$/i then ::RGeo::Features::Point
127
+ when /^linestring$/i then ::RGeo::Features::LineString
128
+ when /^polygon$/i then ::RGeo::Features::Polygon
129
+ when /^geometrycollection$/i then ::RGeo::Features::GeometryCollection
130
+ when /^multipoint$/i then ::RGeo::Features::MultiPoint
131
+ when /^multilinestring$/i then ::RGeo::Features::MultiLineString
132
+ when /^multipolygon$/i then ::RGeo::Features::MultiPolygon
133
+ else nil
134
+ end
135
+ end
136
+
137
+
138
+ def simplified_type(sql_type_)
139
+ sql_type_ =~ /geometry|point|linestring|polygon/i ? :geometry : super
140
+ end
141
+
142
+
143
+ def self.string_to_geometry(str_, ar_class_)
144
+ case str_
145
+ when ::RGeo::Features::Geometry
146
+ str_
147
+ when ::String
148
+ marker_ = str_[4,1]
149
+ little_endian_ = marker_ == "\x01"
150
+ wkt_ = !little_endian_ && marker_ != "\x00"
151
+ srid_ = wkt_ ? 0 : str_[0,4].unpack(little_endian_ ? 'V' : 'N').first
152
+ factory_generator_ = nil
153
+ in_factory_generator_ = ar_class_ ? ar_class_.rgeo_factory_generator : nil
154
+ default_factory_ = ar_class_ ? ar_class_.rgeo_default_factory : nil
155
+ if default_factory_ || in_factory_generator_
156
+ if in_factory_generator_
157
+ default_factory_ ||= factory_generator_.call(:srid => srid_)
158
+ if wkt_
159
+ factory_generator_ = in_factory_generator_
160
+ end
161
+ end
162
+ else
163
+ default_factory_ = ::RGeo::Cartesian.preferred_factory(:srid => srid_)
164
+ if wkt_
165
+ factory_generator_ = ::RGeo::Cartesian.method(:preferred_factory)
166
+ end
167
+ end
168
+ if wkt_
169
+ ::RGeo::WKRep::WKTParser.new(:support_ewkt => true, :default_factory => default_factory_, :factory_generator => factory_generator_).parse(str_)
170
+ else
171
+ ::RGeo::WKRep::WKBParser.new(:default_factory => default_factory_).parse(str_[4..-1])
172
+ end
173
+ else
174
+ nil
175
+ end
176
+ end
177
+
178
+
179
+ end
180
+
181
+
182
+ end
183
+
184
+
185
+ end
186
+
187
+ end
@@ -227,19 +227,24 @@ module RGeo
227
227
  # factory, and will be passed the original object (which may or may
228
228
  # not already be created by this factory), the SFS feature type
229
229
  # (which again may or may not already be the type of the original
230
- # object), a flag indicating whether to keep the subtype if casting
231
- # to a supertype of the current type, and a flag indicating whether
232
- # to force the creation of a new object even if the original is
233
- # already of the desired factory and type.
230
+ # object), and a hash of additional flags. These flags are:
231
+ #
232
+ # <tt>:keep_subtype</tt>::
233
+ # indicates whether to keep the subtype if casting to a supertype
234
+ # of the current type
235
+ # <tt>:force_new</tt>::
236
+ # indicates whether to force the creation of a new object even if
237
+ # the original is already of the desired factory and type.
234
238
  #
235
239
  # It should return either a casted result object, false, or nil.
236
240
  # A nil return value indicates that casting should be forced to
237
241
  # fail (and ::RGeo::Features::cast will return nil).
238
242
  # A false return value indicates that this method declines to
239
243
  # override the casting algorithm, and RGeo should use its default
240
- # algorithm to cast the object.
244
+ # algorithm to cast the object. Therefore, by default, you should
245
+ # return false.
241
246
 
242
- def override_cast(original_, type_, keep_subtype_, force_new_)
247
+ def override_cast(original_, type_, flags_)
243
248
  false
244
249
  end
245
250
 
@@ -0,0 +1,109 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Feature factory interface
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 Features
40
+
41
+
42
+ # A FactoryGenerator is a callable object (usually a Proc) that
43
+ # takes a configuration as a hash and returns a factory. These are
44
+ # often used, e.g., by parsers to determine what factory the parsed
45
+ # geometry should have.
46
+ #
47
+ # See the call method for a list of common configuration parameters.
48
+ # Different generators will support different parameters. There is
49
+ # no mechanism defined to reflect on the capabilities of a factory
50
+ # generator.
51
+ #
52
+ # Many of the implementations provide a factory method for creating
53
+ # factories. For example, RGeo::Cartesian::preferred_factory can be
54
+ # called to create a factory using the preferred Cartesian
55
+ # implementation. Thus, to get a corresponding factory generator,
56
+ # you can use the <tt>method</tt> method. e.g.
57
+ #
58
+ # factory_generator = ::RGeo::Cartesian.method(:preferred_factory)
59
+ #
60
+ # FactoryGenerator is defined as a module and is provided
61
+ # primarily for the sake of documentation. Implementations need not
62
+ # necessarily include this module itself. Therefore, you should not
63
+ # depend on the kind_of? method to determine if an object is a
64
+ # factory generator.
65
+
66
+ module FactoryGenerator
67
+
68
+
69
+ # Generate a factory given a configuration as a hash.
70
+ #
71
+ # If the generator does not recognize or does not support a given
72
+ # configuration value, the behavior is usually determined by the
73
+ # <tt>:strict</tt> configuration element. If <tt>strict</tt> is
74
+ # set to true, the generator should fail fast and return nil or
75
+ # raise an exception. If it is set to false, the generator should
76
+ # attempt to do the best it can, even if it means returning a
77
+ # factory that does not match the requested configuration.
78
+ #
79
+ # Common parameters are as follows. These are intended as a
80
+ # recommendation only. There is no hard requirement for any
81
+ # particular factory generator to support them.
82
+ #
83
+ # <tt>:strict</tt>::
84
+ # If true, return nil or raise an exception if any configuration
85
+ # was not recognized or not supportable. Otherwise, if false,
86
+ # the generator should attempt to do its best to return some
87
+ # viable factory, even if it does not strictly match the
88
+ # requested configuration. Default is usually false.
89
+ # <tt>:srid</tt>::
90
+ # The SRID for the factory and objects it creates.
91
+ # Default is usually 0.
92
+ # <tt>:support_z_coordinate</tt>::
93
+ # Support the <tt>z_coordinate</tt> capability.
94
+ # Default is usually false.
95
+ # <tt>:support_m_coordinate</tt>::
96
+ # Support the <tt>m_coordinate</tt> capability.
97
+ # Default is usually false.
98
+
99
+ def call(config_={})
100
+ nil
101
+ end
102
+
103
+
104
+ end
105
+
106
+
107
+ end
108
+
109
+ end
@@ -160,7 +160,7 @@ module RGeo
160
160
 
161
161
  # Let the factory override
162
162
  if nfactory_.respond_to?(:override_cast)
163
- override_ = nfactory_.override_cast(obj_, ntype_, keep_subtype_, force_new_)
163
+ override_ = nfactory_.override_cast(obj_, ntype_, :keep_subtype => keep_subtype_, :force_new => force_new_)
164
164
  return override_ unless override_ == false
165
165
  end
166
166
 
@@ -207,8 +207,10 @@ module RGeo
207
207
 
208
208
  # See ::RGeo::Features::Factory#override_cast
209
209
 
210
- def override_cast(original_, ntype_, keep_subtype_, force_new_)
210
+ def override_cast(original_, ntype_, flags_)
211
211
  return nil unless Geos.supported?
212
+ keep_subtype_ = flags_[:keep_subtype]
213
+ force_new_ = flags_[:force_new]
212
214
  if GeometryImpl === original_
213
215
  type_ = original_.geometry_type
214
216
  ntype_ = type_ if keep_subtype_ && type_.include?(ntype_)
@@ -53,14 +53,17 @@ module RGeo
53
53
  # constructor, or set on the object afterwards.
54
54
  #
55
55
  # <tt>:default_factory</tt>::
56
- # The default factory for generated geometries, used when no SRID
57
- # is explicitly specified in the input. If none is provided, the
58
- # default cartesian factory will be used.
59
- # <tt>:factory_from_srid</tt>::
60
- # A Proc that takes an SRID as the sole argument, and returns a
61
- # factory for generated geometries when that SRID is specified in
62
- # the input. If no such Proc is provided, the default_factory is
63
- # used, regardless of the input SRID.
56
+ # The default factory for parsed geometries, used when no factory
57
+ # generator is provided. If no default is provided either, the
58
+ # default cartesian factory will be used as the default.
59
+ # <tt>:factory_generator</tt>::
60
+ # A factory generator that should return a factory based on the
61
+ # srid and dimension settings in the input. The factory generator
62
+ # should understand the configuration options <tt>:srid</tt>,
63
+ # <tt>:support_z_coordinate</tt>, and <tt>:support_m_coordinate</tt>.
64
+ # See RGeo::Features::FactoryGenerator for more information.
65
+ # If no generator is provided, the <tt>:default_factory</tt> is
66
+ # used.
64
67
  # <tt>:support_ewkb</tt>::
65
68
  # Activate support for PostGIS EWKB type codes, which use high
66
69
  # order bits in the type code to signal the presence of Z, M, and
@@ -82,7 +85,7 @@ module RGeo
82
85
 
83
86
  def initialize(opts_={})
84
87
  @default_factory = opts_[:default_factory] || Cartesian.preferred_factory
85
- @factory_from_srid = opts_[:factory_from_srid]
88
+ @factory_generator = opts_[:factory_generator]
86
89
  @support_ewkb = opts_[:support_ewkb] ? true : false
87
90
  @support_wkb12 = opts_[:support_wkb12] ? true : false
88
91
  @ignore_extra_bytes = opts_[:ignore_extra_bytes] ? true : false
@@ -99,21 +102,21 @@ module RGeo
99
102
  @default_factory = value_ || Cartesian.preferred_factory
100
103
  end
101
104
 
102
- # Returns true if this parser has a factory_from_srid procedure.
105
+ # Returns the factory generator, or nil if there is none.
103
106
  # See WKBParser for details.
104
- def has_factory_from_srid?
105
- @factory_from_srid ? true : false
107
+ def factory_generator
108
+ @factory_generator
106
109
  end
107
110
 
108
- # Sets the factory_from_srid. See WKBParser for details.
109
- def factory_from_srid=(value_)
110
- @factory_from_srid = value_
111
+ # Sets the factory_generator. See WKBParser for details.
112
+ def factory_generator=(value_)
113
+ @factory_generator = value_
111
114
  end
112
115
 
113
- # Sets the factory_from_srid to the given block.
116
+ # Sets the factory_generator to the given block.
114
117
  # See WKBParser for details.
115
- def set_factory_from_srid(&block_)
116
- @factory_from_srid = block_
118
+ def to_generate_factory(&block_)
119
+ @factory_generator = block_
117
120
  end
118
121
 
119
122
  # Returns true if this parser supports EWKB.
@@ -215,9 +218,9 @@ module RGeo
215
218
  @cur_has_z = has_z_
216
219
  @cur_has_m = has_m_
217
220
  @cur_dims = 2 + (@cur_has_z ? 1 : 0) + (@cur_has_m ? 1 : 0)
218
- @cur_srid = srid_
219
- if srid_ && @factory_from_srid
220
- @cur_factory = @factory_from_srid.call(srid_)
221
+ @cur_srid = srid_.to_i
222
+ if @factory_generator
223
+ @cur_factory = @factory_generator.call(:srid => @cur_srid, :support_z_coordinate => has_z_, :support_m_coordinate => has_m_)
221
224
  end
222
225
  if @cur_has_z && !@cur_factory.has_capability?(:z_coordinate)
223
226
  raise Errors::ParseError, "Data has Z coordinates but the factory doesn't have z_coordinate capability"