activerecord-spatialite-adapter 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.rdoc CHANGED
@@ -1,3 +1,11 @@
1
+ === 0.3.0 / 2011-01-26
2
+
3
+ * Reworked type and constraint handling, which should result in a large number of bug fixes, especially related to schema dumps.
4
+ * Experimental support for complex spatial queries. (Requires Arel 2.1, which is expected to be released with Rails 3.1.)
5
+ * API CHANGE: The indexes method now returns all indexes including spatial indexes; removed the separate spatial_indexes method.
6
+ * The path to the Railtie is now different (see the README), though a compatibility wrapper has been left in the old location.
7
+ * Reorganized the code a bit for better clarity.
8
+
1
9
  === 0.2.3 / 2011-01-06
2
10
 
3
11
  * Many of ActiveRecord's rake tasks weren't working because they need to know about every adapter explicitly. I hesitate to call this "fixed" since I see it as a problem in ActiveRecord, but we now at least have a workaround so the rake tasks will run properly. (Reported by Tad Thorley.)
data/README.rdoc CHANGED
@@ -7,7 +7,9 @@ the {RGeo}[http://github.com/dazuma/rgeo] library to represent spatial
7
7
  data in Ruby. Like the standard sqlite3 adapter, this adapter requires
8
8
  the sqlite3-ruby gem.
9
9
 
10
- === What This Adapter Provides
10
+ == What This Adapter Provides
11
+
12
+ === Spatial Migrations
11
13
 
12
14
  First, this adapter extends the migration syntax to support creating
13
15
  spatial columns and indexes. To create a spatial column, use the
@@ -17,24 +19,29 @@ the <tt>:spatial</tt> option to true.
17
19
 
18
20
  Examples:
19
21
 
20
- create_table :spatial_table do |t|
21
- t.column :latlon, :point # or t.point :latlon
22
- t.line_string :path
23
- t.geometry :shape
24
- end
25
- change_table :spatial_table do |t|
26
- t.index :latlon, :spatial => true
27
- end
22
+ create_table :my_spatial_table do |t|
23
+ t.column :latlon, :point # or t.point :latlon
24
+ t.line_string :path
25
+ t.geometry :shape
26
+ end
27
+ change_table :my_spatial_table do |t|
28
+ t.index :latlon, :spatial => true
29
+ end
30
+
31
+ === Spatial Attributes
28
32
 
29
33
  When this adapter is in use, spatial attributes in your \ActiveRecord
30
34
  objects will have RGeo geometry values. You can set spatial attributes
31
35
  either to RGeo geometry objects, or to strings in WKT (well-known text)
32
36
  format, which the adapter will automatically convert to geometry objects.
33
37
 
34
- To specify the RGeo geometry factory, you can either set an explicit
35
- factory for a column, or provide a factory generator that will yield the
36
- appropriate factory for the table's spatial columns based on the value.
37
- For the former, call the set_rgeo_factory_for_column class method on your
38
+ Spatial objects in RGeo are tied to a factory that specifies the
39
+ coordinate system as well as other behaviors of the object. You must
40
+ therefore specify a factory for each spatial column (attribute) in your
41
+ ActiveRecord class. You can either set an explicit factory for a specific
42
+ column, or provide a factory generator that will yield the appropriate
43
+ factory for the table's spatial columns based on their types. For the
44
+ former, call the <tt>set_rgeo_factory_for_column</tt> class method on your
38
45
  \ActiveRecord class. For the latter, set the rgeo_factory_generator class
39
46
  attribute. This generator should understand at least the <tt>:srid</tt>
40
47
  option, which will be provided based on the column's specified SRID. Note
@@ -45,39 +52,45 @@ actually implemented and documented in the "rgeo-activerecord" gem.
45
52
 
46
53
  Examples, given the spatial table defined above:
47
54
 
48
- class SpatialTable < ActiveRecord::Base
49
-
50
- # By default, use the GEOS implementation for spatial columns.
51
- self.rgeo_factory_generator = RGeo::Geos.method(:factory)
52
-
53
- # But use a geographic implementation for the :latlon column.
54
- set_rgeo_factory_for_column(:latlon, RGeo::Geographic.spherical_factory)
55
-
56
- end
55
+ class MySpatialTable < ActiveRecord::Base
56
+
57
+ # By default, use the GEOS implementation for spatial columns.
58
+ self.rgeo_factory_generator = RGeo::Geos.method(:factory)
59
+
60
+ # But use a geographic implementation for the :latlon column.
61
+ set_rgeo_factory_for_column(:latlon, RGeo::Geographic.spherical_factory)
62
+
63
+ end
57
64
 
58
65
  Now you can interact with the data using the RGeo types:
59
66
 
60
- rec = SpatialTable.new
61
- rec.latlon = 'POINT(-122 47)' # You can set by feature object or WKT.
62
- loc = rec.latlon # Accessing always returns a feature object, in
63
- # this case, a geographic that understands latitude.
64
- loc.latitude # => 47
65
- rec.shape = loc # the factory for the :shape column is GEOS, so the
66
- # value will be cast from geographic to GEOS.
67
- RGeo::Geos.is_geos?(rec.shape) # => true
67
+ rec = MySpatialTable.new
68
+ rec.latlon = 'POINT(-122 47)' # You can set by feature object or WKT.
69
+ loc = rec.latlon # Accessing always returns a feature object, in
70
+ # this case, a geographic that understands latitude.
71
+ loc.latitude # => 47
72
+ rec.shape = loc # the factory for the :shape column is GEOS, so the
73
+ # value will be cast from geographic to GEOS.
74
+ RGeo::Geos.is_geos?(rec.shape) # => true
75
+
76
+ === Spatial Queries
68
77
 
69
78
  You can create simple queries based on spatial equality in the same way
70
79
  you would on a scalar column:
71
80
 
72
- rec = SpatialTable.where(:latlon => RGeo::Geos.factory.point(-122, 47)).first
81
+ rec = MySpatialTable.where(:latlon => RGeo::Geos.factory.point(-122, 47)).first
73
82
 
74
83
  You can also use WKT:
75
84
 
76
- rec = SpatialTable.where(:latlon => 'POINT(-122 47)').first
85
+ rec = MySpatialTable.where(:latlon => 'POINT(-122 47)').first
86
+
87
+ The adapter also provides experimental support for more complex queries
88
+ such as radius searches. However, these extensions require Arel 2.1
89
+ (which is scheduled for release with Rails 3.1). We do not have these
90
+ documented yet, and the syntax is subject to change. For now, you should
91
+ write more complex queries in SQL.
77
92
 
78
- Other types of queries currently must be written in SQL. However, we are
79
- investigating writing a set of Arel extensions for constructing arbitrary
80
- spatial queries.
93
+ == Installation And Configuration
81
94
 
82
95
  === Installing The Adapter Gem
83
96
 
@@ -87,12 +100,12 @@ This adapter has the following requirements:
87
100
  * SpatiaLite 2.3 or later (2.4 recommended).
88
101
  * \ActiveRecord 3.0.3 or later. Earlier versions will not work.
89
102
  * rgeo gem 0.2.4 or later.
90
- * rgeo-activerecord gem 0.2.2 or later.
91
- * sqlite3 gem 1.3 or later.
103
+ * rgeo-activerecord gem 0.3.0 or later.
104
+ * sqlite3 gem 1.3.3 or later.
92
105
 
93
106
  Install this adapter as a gem:
94
107
 
95
- gem install activerecord-spatialite-adapter
108
+ gem install activerecord-spatialite-adapter
96
109
 
97
110
  See the README for the "rgeo" gem, a required dependency, for further
98
111
  installation information.
@@ -109,16 +122,55 @@ which should be set to the full path to the libspatialite shared library,
109
122
  if it is not installed in a standard place (such as /usr/local or
110
123
  /opt/local).
111
124
 
112
- Furthermore, the SpatiaLite adapter includes a special railtie that
113
- provides support for SpatiaLite databases in ActiveRecord's rake tasks.
114
- This railtie is required in order to run, e.g., rake test. To install
115
- this railtie, you should add this line to your config/application.rb:
125
+ Generally, you can create a new Rails application using:
116
126
 
117
- require 'rgeo/active_record/spatialite_adapter/railtie'
127
+ rails new my_app --database=sqlite3
128
+
129
+ ...and then change the adapter names to "<tt>spatialite</tt>" and add an
130
+ appropriate <tt>libspatialite</tt> setting.
131
+
132
+ Next, the SpatiaLite adapter includes a special railtie that provides
133
+ support for SpatiaLite databases in ActiveRecord's rake tasks. This
134
+ railtie is required in order to run, e.g., rake test. To install this
135
+ railtie, you should add this line to your config/application.rb:
136
+
137
+ require 'active_record/connection_adapters/spatialite_adapter/railtie'
118
138
 
119
139
  Note that this railtie must load after the ActiveRecord railtie. That is,
120
140
  the above require command should appear after <tt>require 'rails/all'</tt>.
121
141
 
142
+ === Dealing with SpatiaLite Definitions
143
+
144
+ SpatiaLite adds many objects (meta-information tables, functions,
145
+ triggers, etc.) to a Sqlite3 database. These objects are required to
146
+ maintain the spatial elements of the database, but they can be a hassle
147
+ when managing the database with Rails. Following are some tips and
148
+ gotchas that you may encounter.
149
+
150
+ Make sure you include the correct <tt>libspatialite</tt> setting in your
151
+ database.yml config file, especially for your production environments.
152
+
153
+ SpatiaLite databases need to be initialized by executing the SpatiaLite
154
+ initialization script or by calling the InitSpatialMetaData() function.
155
+ The rake db:create task will do this for you when it creates a database.
156
+ Thus, when setting up a new application, you should make sure you call
157
+ rake db:create or otherwise cause the SpatiaLite initialization to
158
+ occur, before you attempt to run your first migration. Failure to do so
159
+ will result in errors during the migration.
160
+
161
+ Dumping a SpatiaLite database as SQL will cause a bunch of internal tables
162
+ and triggers to be included in your dump. These are the actual SpatiaLite
163
+ implementation objects used to enforce spatial constraints and implement
164
+ spatial indexes. Unfortunately, not only is this a bit unsightly, but not
165
+ everything is dumped here: for example, for each spatial column, there
166
+ should be a row in the geometry_columns table, and those will be missing
167
+ in the SQL structure dump. As a result, loading from the SQL structure
168
+ dump will not properly reproduce your database schema. Because of this, we
169
+ highly recommend that you leave config.active_record.schema_format set to
170
+ <tt>:ruby</tt> for now, so that schema dumps are done in the Ruby format.
171
+
172
+ == Additional Information
173
+
122
174
  === Known bugs and limitations
123
175
 
124
176
  The spatialite adapter works in principle, but there are a few known holes
@@ -145,7 +197,8 @@ Contact the author at dazuma at gmail dot com.
145
197
 
146
198
  === Acknowledgments
147
199
 
148
- RGeo is written by Daniel Azuma (http://www.daniel-azuma.com).
200
+ The SpatiaLite Adapter and its supporting libraries (including RGeo) are
201
+ written by Daniel Azuma (http://www.daniel-azuma.com).
149
202
 
150
203
  Development of RGeo is sponsored by GeoPage, Inc. (http://www.geopage.com).
151
204
 
data/Version CHANGED
@@ -1 +1 @@
1
- 0.2.3
1
+ 0.3.0
@@ -38,33 +38,6 @@ require 'rgeo/active_record'
38
38
  require 'active_record/connection_adapters/sqlite3_adapter'
39
39
 
40
40
 
41
- # :stopdoc:
42
-
43
- module Arel
44
- module Visitors
45
-
46
- class SpatiaLite < SQLite
47
-
48
- FUNC_MAP = {
49
- 'ST_WKTToSQL' => 'GeomFromText',
50
- }
51
-
52
- include ::RGeo::ActiveRecord::SpatialToSql
53
-
54
- def st_func(standard_name_)
55
- FUNC_MAP[standard_name_] || standard_name_
56
- end
57
-
58
- end
59
-
60
- VISITORS['spatialite'] = ::Arel::Visitors::SpatiaLite
61
-
62
- end
63
- end
64
-
65
- # :startdoc:
66
-
67
-
68
41
  # The activerecord-spatialite-adapter gem installs the *spatialite*
69
42
  # connection adapter into ActiveRecord.
70
43
 
@@ -122,418 +95,42 @@ module ActiveRecord
122
95
  db_.enable_load_extension(1)
123
96
  db_.load_extension(path_)
124
97
 
125
- ConnectionAdapters::SpatiaLiteAdapter.new(db_, logger, config_)
98
+ ::ActiveRecord::ConnectionAdapters::SpatiaLiteAdapter::MainAdapter.new(db_, logger, config_)
126
99
  end
127
100
 
128
101
 
129
102
  end
130
103
 
131
104
 
132
- module ConnectionAdapters # :nodoc:
133
-
105
+ # All ActiveRecord adapters go in this namespace.
106
+ module ConnectionAdapters
134
107
 
135
- class SpatiaLiteAdapter < SQLite3Adapter # :nodoc:
136
-
108
+ # The SpatiaLite Adapter
109
+ module SpatiaLiteAdapter
137
110
 
111
+ # The name returned by the adapter_name method of this adapter.
138
112
  ADAPTER_NAME = 'SpatiaLite'.freeze
139
113
 
140
- @@native_database_types = nil
141
-
142
-
143
- def native_database_types
144
- unless @@native_database_types
145
- @@native_database_types = super.dup
146
- @@native_database_types.merge!(:geometry => {:name => "geometry"}, :point => {:name => "point"}, :line_string => {:name => "linestring"}, :polygon => {:name => "polygon"}, :geometry_collection => {:name => "geometrycollection"}, :multi_point => {:name => "multipoint"}, :multi_line_string => {:name => "multilinestring"}, :multi_polygon => {:name => "multipolygon"})
147
- end
148
- @@native_database_types
149
- end
150
-
151
-
152
- def adapter_name
153
- ADAPTER_NAME
154
- end
155
-
156
-
157
- def spatialite_version
158
- @spatialite_version ||= SQLiteAdapter::Version.new(select_value('SELECT spatialite_version()'))
159
- end
160
-
161
-
162
- def srs_database_columns
163
- {:name_column => 'ref_sys_name', :proj4text_column => 'proj4text', :auth_name_column => 'auth_name', :auth_srid_column => 'auth_srid'}
164
- end
165
-
166
-
167
- def quote(value_, column_=nil)
168
- if ::RGeo::Feature::Geometry.check_type(value_)
169
- "GeomFromWKB(X'#{::RGeo::WKRep::WKBGenerator.new(:hex_format => true).generate(value_)}', #{value_.srid})"
170
- else
171
- super
172
- end
173
- end
174
-
175
-
176
- def columns(table_name_, name_=nil) #:nodoc:
177
- spatial_info_ = spatial_column_info(table_name_)
178
- table_structure(table_name_).map do |field_|
179
- col_ = SpatialColumn.new(field_['name'], field_['dflt_value'], field_['type'], field_['notnull'].to_i == 0)
180
- info_ = spatial_info_[field_['name']]
181
- if info_
182
- col_.set_srid(info_[:srid])
183
- end
184
- col_
185
- end
186
- end
187
-
188
-
189
- def spatial_indexes(table_name_, name_=nil)
190
- table_name_ = table_name_.to_s
191
- names_ = select_values("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'idx_#{quote_string(table_name_)}_%' AND rootpage=0") || []
192
- names_.map do |name_|
193
- col_name_ = name_.sub("idx_#{table_name_}_", '')
194
- ::RGeo::ActiveRecord::SpatialIndexDefinition.new(table_name_, name_, false, [col_name_], [], true)
195
- end
196
- end
197
-
198
-
199
- def create_table(table_name_, options_={})
200
- table_name_ = table_name_.to_s
201
- table_definition_ = SpatialTableDefinition.new(self)
202
- table_definition_.primary_key(options_[:primary_key] || ::ActiveRecord::Base.get_primary_key(table_name_.singularize)) unless options_[:id] == false
203
- yield table_definition_ if block_given?
204
- if options_[:force] && table_exists?(table_name_)
205
- drop_table(table_name_, options_)
206
- end
207
-
208
- create_sql_ = "CREATE#{' TEMPORARY' if options_[:temporary]} TABLE "
209
- create_sql_ << "#{quote_table_name(table_name_)} ("
210
- create_sql_ << table_definition_.to_sql
211
- create_sql_ << ") #{options_[:options]}"
212
- execute create_sql_
213
-
214
- table_definition_.spatial_columns.each do |col_|
215
- execute("SELECT AddGeometryColumn('#{quote_string(table_name_)}', '#{quote_string(col_.name.to_s)}', #{col_.srid}, '#{quote_string(col_.type.to_s.gsub('_','').upcase)}', 'XY', #{col_.null ? 0 : 1})")
216
- end
217
- end
218
-
219
-
220
- def drop_table(table_name_, options_={})
221
- spatial_indexes(table_name_).each do |index_|
222
- remove_index(table_name_, :spatial => true, :column => index_.columns[0])
223
- end
224
- execute("DELETE from geometry_columns where f_table_name='#{quote_string(table_name_.to_s)}'")
225
- super
226
- end
227
-
228
-
229
- def add_column(table_name_, column_name_, type_, options_={})
230
- if ::RGeo::ActiveRecord::GEOMETRY_TYPES.include?(type_.to_sym)
231
- execute("SELECT AddGeometryColumn('#{quote_string(table_name_.to_s)}', '#{quote_string(column_name_.to_s)}', #{options_[:srid].to_i}, '#{quote_string(type_.to_s)}', 'XY', #{options_[:null] == false ? 0 : 1})")
232
- else
233
- super
234
- end
235
- end
236
-
237
-
238
- def add_index(table_name_, column_name_, options_={})
239
- if options_[:spatial]
240
- column_name_ = column_name_.first if column_name_.kind_of?(::Array) && column_name_.size == 1
241
- table_name_ = table_name_.to_s
242
- column_name_ = column_name_.to_s
243
- spatial_info_ = spatial_column_info(table_name_)
244
- unless spatial_info_[column_name_]
245
- raise ::ArgumentError, "Can't create spatial index because column '#{column_name_}' in table '#{table_name_}' is not a geometry column"
246
- end
247
- result_ = select_value("SELECT CreateSpatialIndex('#{quote_string(table_name_)}', '#{quote_string(column_name_)}')").to_i
248
- if result_ == 0
249
- raise ::ArgumentError, "Spatial index already exists on table '#{table_name_}', column '#{column_name_}'"
250
- end
251
- result_
252
- else
253
- super
254
- end
255
- end
256
-
257
-
258
- def remove_index(table_name_, options_={})
259
- if options_[:spatial]
260
- table_name_ = table_name_.to_s
261
- column_ = options_[:column]
262
- if column_
263
- column_ = column_[0] if column_.kind_of?(::Array)
264
- column_ = column_.to_s
265
- else
266
- index_name_ = options_[:name]
267
- unless index_name_
268
- raise ::ArgumentError, "You need to specify a column or index name to remove a spatial index."
269
- end
270
- if index_name_ =~ /^idx_#{table_name_}_(\w+)$/
271
- column_ = $1
272
- else
273
- raise ::ArgumentError, "Unknown spatial index name: #{index_name_.inspect}."
274
- end
275
- end
276
- spatial_info_ = spatial_column_info(table_name_)
277
- unless spatial_info_[column_]
278
- raise ::ArgumentError, "Can't remove spatial index because column '#{column_}' in table '#{table_name_}' is not a geometry column"
279
- end
280
- index_name_ = "idx_#{table_name_}_#{column_}"
281
- has_index_ = select_value("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='#{quote_string(index_name_)}'").to_i > 0
282
- unless has_index_
283
- raise ::ArgumentError, "Spatial index not present on table '#{table_name_}', column '#{column_}'"
284
- end
285
- execute("SELECT DisableSpatialIndex('#{quote_string(table_name_)}', '#{quote_string(column_)}')")
286
- execute("DROP TABLE #{quote_table_name(index_name_)}")
287
- else
288
- super
289
- end
290
- end
291
-
292
-
293
- def spatial_column_info(table_name_)
294
- info_ = execute("SELECT * FROM geometry_columns WHERE f_table_name='#{quote_string(table_name_.to_s)}'")
295
- result_ = {}
296
- info_.each do |row_|
297
- result_[row_['f_geometry_column']] = {
298
- :name => row_['f_geometry_column'],
299
- :type => row_['type'],
300
- :dimension => row_['coord_dimension'],
301
- :srid => row_['srid'],
302
- :has_index => row_['spatial_index_enabled'],
303
- }
304
- end
305
- result_
306
- end
307
-
308
-
309
- class SpatialTableDefinition < ConnectionAdapters::TableDefinition # :nodoc:
310
-
311
- attr_reader :spatial_columns
312
-
313
- def initialize(base_)
314
- super
315
- end
316
-
317
- def column(name_, type_, options_={})
318
- super
319
- col_ = self[name_]
320
- if ::RGeo::ActiveRecord::GEOMETRY_TYPES.include?(col_.type.to_sym)
321
- col_.extend(GeometricColumnDefinitionMethods) unless col_.respond_to?(:srid)
322
- col_.set_srid(options_[:srid].to_i)
323
- end
324
- self
325
- end
326
-
327
- def to_sql
328
- @columns.find_all{ |c_| !c_.respond_to?(:srid) }.map{ |c_| c_.to_sql } * ', '
329
- end
330
-
331
- def spatial_columns
332
- @columns.find_all{ |c_| c_.respond_to?(:srid) }
333
- end
334
-
335
- end
336
-
337
-
338
- module GeometricColumnDefinitionMethods # :nodoc:
339
-
340
- def srid
341
- defined?(@srid) ? @srid : 4326
342
- end
343
-
344
- def set_srid(value_)
345
- @srid = value_
346
- end
347
-
348
- end
349
-
350
-
351
- class SpatialColumn < ConnectionAdapters::SQLiteColumn # :nodoc:
352
-
353
-
354
- def initialize(name_, default_, sql_type_=nil, null_=true)
355
- super(name_, default_, sql_type_, null_)
356
- @geometric_type = ::RGeo::ActiveRecord.geometric_type_from_name(sql_type_)
357
- @ar_class = ::ActiveRecord::Base
358
- @srid = 0
359
- end
360
-
361
-
362
- def set_ar_class(val_)
363
- @ar_class = val_
364
- end
365
-
366
- def set_srid(val_)
367
- @srid = val_
368
- end
369
-
370
-
371
- attr_reader :srid
372
- attr_reader :geometric_type
373
-
374
-
375
- def spatial?
376
- type == :geometry
377
- end
378
-
379
-
380
- def klass
381
- type == :geometry ? ::RGeo::Feature::Geometry : super
382
- end
383
-
384
-
385
- def type_cast(value_)
386
- type == :geometry ? SpatialColumn.convert_to_geometry(value_, @ar_class, name, @srid) : super
387
- end
388
-
389
-
390
- def type_cast_code(var_name_)
391
- type == :geometry ? "::ActiveRecord::ConnectionAdapters::SpatiaLiteAdapter::SpatialColumn.convert_to_geometry(#{var_name_}, self.class, #{name.inspect}, #{@srid})" : super
392
- end
393
-
394
-
395
- private
396
-
397
-
398
- def simplified_type(sql_type_)
399
- sql_type_ =~ /geometry|point|linestring|polygon/i ? :geometry : super
400
- end
401
-
402
-
403
- def self.convert_to_geometry(input_, ar_class_, column_name_, column_srid_)
404
- case input_
405
- when ::RGeo::Feature::Geometry
406
- factory_ = ar_class_.rgeo_factory_for_column(column_name_, :srid => column_srid_)
407
- ::RGeo::Feature.cast(input_, factory_)
408
- when ::String
409
- if input_.length == 0
410
- nil
411
- else
412
- factory_ = ar_class_.rgeo_factory_for_column(column_name_, :srid => column_srid_)
413
- if input_[0,1] == "\x00"
414
- NativeFormatParser.new(factory_).parse(input_) rescue nil
415
- else
416
- ::RGeo::WKRep::WKTParser.new(factory_, :support_ewkt => true).parse(input_)
417
- end
418
- end
419
- else
420
- nil
421
- end
422
- end
423
-
424
-
425
- end
426
-
427
-
428
- class NativeFormatParser # :nodoc:
429
-
430
-
431
- def initialize(factory_)
432
- @factory = factory_
433
- end
434
-
435
-
436
- def parse(data_)
437
- @little_endian = data_[1,1] == "\x01"
438
- srid_ = data_[2,4].unpack(@little_endian ? 'V' : 'N').first
439
- begin
440
- _start_scanner(data_)
441
- obj_ = _parse_object(false)
442
- _get_byte(0xfe)
443
- ensure
444
- _clean_scanner
445
- end
446
- obj_
447
- end
448
-
449
-
450
- def _parse_object(contained_)
451
- _get_byte(contained_ ? 0x69 : 0x7c)
452
- type_code_ = _get_integer
453
- case type_code_
454
- when 1
455
- coords_ = _get_doubles(2)
456
- @factory.point(*coords_)
457
- when 2
458
- _parse_line_string
459
- when 3
460
- interior_rings_ = (1.._get_integer).map{ _parse_line_string }
461
- exterior_ring_ = interior_rings_.shift || @factory.linear_ring([])
462
- @factory.polygon(exterior_ring_, interior_rings_)
463
- when 4
464
- @factory.multi_point((1.._get_integer).map{ _parse_object(1) })
465
- when 5
466
- @factory.multi_line_string((1.._get_integer).map{ _parse_object(2) })
467
- when 6
468
- @factory.multi_polygon((1.._get_integer).map{ _parse_object(3) })
469
- when 7
470
- @factory.collection((1.._get_integer).map{ _parse_object(true) })
471
- else
472
- raise ::RGeo::Error::ParseError, "Unknown type value: #{type_code_}."
473
- end
474
- end
475
-
476
-
477
- def _parse_line_string
478
- count_ = _get_integer
479
- coords_ = _get_doubles(2 * count_)
480
- @factory.line_string((0...count_).map{ |i_| @factory.point(*coords_[2*i_,2]) })
481
- end
482
-
483
-
484
- def _start_scanner(data_)
485
- @_data = data_
486
- @_len = data_.length
487
- @_pos = 38
488
- end
489
-
490
-
491
- def _clean_scanner
492
- @_data = nil
493
- end
494
-
495
-
496
- def _get_byte(expect_=nil)
497
- if @_pos + 1 > @_len
498
- raise ::RGeo::Error::ParseError, "Not enough bytes left to fulfill 1 byte"
499
- end
500
- str_ = @_data[@_pos, 1]
501
- @_pos += 1
502
- val_ = str_.unpack("C").first
503
- if expect_ && expect_ != val_
504
- raise ::RGeo::Error::ParseError, "Expected byte 0x#{expect_.to_s(16)} but got 0x#{val_.to_s(16)}"
505
- end
506
- val_
507
- end
508
-
509
-
510
- def _get_integer
511
- if @_pos + 4 > @_len
512
- raise ::RGeo::Error::ParseError, "Not enough bytes left to fulfill 1 integer"
513
- end
514
- str_ = @_data[@_pos, 4]
515
- @_pos += 4
516
- str_.unpack("#{@little_endian ? 'V' : 'N'}").first
517
- end
518
-
519
-
520
- def _get_doubles(count_)
521
- len_ = 8 * count_
522
- if @_pos + len_ > @_len
523
- raise ::RGeo::Error::ParseError, "Not enough bytes left to fulfill #{count_} doubles"
524
- end
525
- str_ = @_data[@_pos, len_]
526
- @_pos += len_
527
- str_.unpack("#{@little_endian ? 'E' : 'G'}*")
528
- end
529
-
530
-
531
- end
532
-
533
-
534
114
  end
535
115
 
536
116
  end
537
117
 
538
118
 
539
119
  end
120
+
121
+
122
+ require 'active_record/connection_adapters/spatialite_adapter/version.rb'
123
+ require 'active_record/connection_adapters/spatialite_adapter/native_format_parser.rb'
124
+ require 'active_record/connection_adapters/spatialite_adapter/main_adapter.rb'
125
+ require 'active_record/connection_adapters/spatialite_adapter/spatial_table_definition.rb'
126
+ require 'active_record/connection_adapters/spatialite_adapter/spatial_column.rb'
127
+ require 'active_record/connection_adapters/spatialite_adapter/arel_tosql.rb'
128
+
129
+
130
+ ignore_tables_ = ::ActiveRecord::SchemaDumper.ignore_tables
131
+ ignore_tables_ << 'geometry_columns' unless ignore_tables_.include?('geometry_columns')
132
+ ignore_tables_ << 'geometry_columns_auth' unless ignore_tables_.include?('geometry_columns_auth')
133
+ ignore_tables_ << 'views_geometry_columns' unless ignore_tables_.include?('views_geometry_columns')
134
+ ignore_tables_ << 'virts_geometry_columns' unless ignore_tables_.include?('virts_geometry_columns')
135
+ ignore_tables_ << 'spatial_ref_sys' unless ignore_tables_.include?('spatial_ref_sys')
136
+ ignore_tables_ << /^idx_\w+_\w+$/ unless ignore_tables_.include?(/^idx_\w+_\w+$/)