rgeo 0.1.22 → 0.2.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.
Files changed (86) hide show
  1. data/History.rdoc +31 -0
  2. data/README.rdoc +53 -59
  3. data/Spatial_Programming_With_RGeo.rdoc +120 -67
  4. data/Version +1 -1
  5. data/ext/proj4_c_impl/extconf.rb +1 -1
  6. data/lib/rgeo.rb +80 -87
  7. data/lib/rgeo/cartesian.rb +0 -10
  8. data/lib/rgeo/coord_sys.rb +0 -7
  9. data/lib/rgeo/coord_sys/proj4.rb +2 -2
  10. data/lib/rgeo/error.rb +2 -6
  11. data/lib/rgeo/feature.rb +0 -7
  12. data/lib/rgeo/feature/curve.rb +5 -5
  13. data/lib/rgeo/feature/factory.rb +45 -5
  14. data/lib/rgeo/feature/factory_generator.rb +2 -4
  15. data/lib/rgeo/feature/geometry.rb +97 -27
  16. data/lib/rgeo/feature/geometry_collection.rb +3 -3
  17. data/lib/rgeo/feature/line_string.rb +3 -3
  18. data/lib/rgeo/feature/multi_curve.rb +2 -2
  19. data/lib/rgeo/feature/multi_surface.rb +3 -3
  20. data/lib/rgeo/feature/point.rb +6 -6
  21. data/lib/rgeo/feature/polygon.rb +4 -4
  22. data/lib/rgeo/feature/surface.rb +3 -3
  23. data/lib/rgeo/geographic.rb +0 -11
  24. data/lib/rgeo/geographic/factory.rb +5 -2
  25. data/lib/rgeo/geographic/interface.rb +1 -1
  26. data/lib/rgeo/geos.rb +0 -7
  27. data/lib/rgeo/geos/factory.rb +1 -1
  28. data/lib/rgeo/impl_helper.rb +0 -7
  29. data/lib/rgeo/wkrep.rb +0 -7
  30. data/lib/rgeo/wkrep/wkb_parser.rb +2 -2
  31. data/test/tc_oneoff.rb +0 -1
  32. metadata +7 -155
  33. data/lib/active_record/connection_adapters/mysql2spatial_adapter.rb +0 -124
  34. data/lib/active_record/connection_adapters/mysqlspatial_adapter.rb +0 -136
  35. data/lib/active_record/connection_adapters/postgis_adapter.rb +0 -426
  36. data/lib/active_record/connection_adapters/spatialite_adapter.rb +0 -488
  37. data/lib/rgeo/active_record/arel_modifications.rb +0 -78
  38. data/lib/rgeo/active_record/base_modifications.rb +0 -124
  39. data/lib/rgeo/active_record/common.rb +0 -166
  40. data/lib/rgeo/active_record/mysql_common.rb +0 -150
  41. data/lib/rgeo/all.rb +0 -49
  42. data/lib/rgeo/geo_json.rb +0 -60
  43. data/lib/rgeo/geo_json/coder.rb +0 -401
  44. data/lib/rgeo/geo_json/entities.rb +0 -285
  45. data/lib/rgeo/geo_json/interface.rb +0 -129
  46. data/lib/rgeo/shapefile.rb +0 -60
  47. data/lib/rgeo/shapefile/reader.rb +0 -898
  48. data/test/active_record/common_setup_methods.rb +0 -129
  49. data/test/active_record/readme.txt +0 -43
  50. data/test/active_record/tc_mysqlspatial.rb +0 -170
  51. data/test/active_record/tc_postgis.rb +0 -282
  52. data/test/active_record/tc_spatialite.rb +0 -198
  53. data/test/shapefile/shapelib_testcases/readme.txt +0 -11
  54. data/test/shapefile/shapelib_testcases/test.dbf +0 -0
  55. data/test/shapefile/shapelib_testcases/test.shp +0 -0
  56. data/test/shapefile/shapelib_testcases/test.shx +0 -0
  57. data/test/shapefile/shapelib_testcases/test0.shp +0 -0
  58. data/test/shapefile/shapelib_testcases/test0.shx +0 -0
  59. data/test/shapefile/shapelib_testcases/test1.shp +0 -0
  60. data/test/shapefile/shapelib_testcases/test1.shx +0 -0
  61. data/test/shapefile/shapelib_testcases/test10.shp +0 -0
  62. data/test/shapefile/shapelib_testcases/test10.shx +0 -0
  63. data/test/shapefile/shapelib_testcases/test11.shp +0 -0
  64. data/test/shapefile/shapelib_testcases/test11.shx +0 -0
  65. data/test/shapefile/shapelib_testcases/test12.shp +0 -0
  66. data/test/shapefile/shapelib_testcases/test12.shx +0 -0
  67. data/test/shapefile/shapelib_testcases/test13.shp +0 -0
  68. data/test/shapefile/shapelib_testcases/test13.shx +0 -0
  69. data/test/shapefile/shapelib_testcases/test2.shp +0 -0
  70. data/test/shapefile/shapelib_testcases/test2.shx +0 -0
  71. data/test/shapefile/shapelib_testcases/test3.shp +0 -0
  72. data/test/shapefile/shapelib_testcases/test3.shx +0 -0
  73. data/test/shapefile/shapelib_testcases/test4.shp +0 -0
  74. data/test/shapefile/shapelib_testcases/test4.shx +0 -0
  75. data/test/shapefile/shapelib_testcases/test5.shp +0 -0
  76. data/test/shapefile/shapelib_testcases/test5.shx +0 -0
  77. data/test/shapefile/shapelib_testcases/test6.shp +0 -0
  78. data/test/shapefile/shapelib_testcases/test6.shx +0 -0
  79. data/test/shapefile/shapelib_testcases/test7.shp +0 -0
  80. data/test/shapefile/shapelib_testcases/test7.shx +0 -0
  81. data/test/shapefile/shapelib_testcases/test8.shp +0 -0
  82. data/test/shapefile/shapelib_testcases/test8.shx +0 -0
  83. data/test/shapefile/shapelib_testcases/test9.shp +0 -0
  84. data/test/shapefile/shapelib_testcases/test9.shx +0 -0
  85. data/test/shapefile/tc_shapelib_tests.rb +0 -527
  86. data/test/tc_geojson.rb +0 -279
@@ -1,124 +0,0 @@
1
- # -----------------------------------------------------------------------------
2
- #
3
- # MysqlSpatial 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
- require 'rgeo/active_record/mysql_common'
38
- require 'active_record/connection_adapters/mysql2_adapter'
39
-
40
-
41
- module ActiveRecord
42
-
43
- class Base
44
-
45
-
46
- # Create a mysql2spatial connection adapter
47
-
48
- def self.mysql2spatial_connection(config_)
49
- config_[:username] = 'root' if config_[:username].nil?
50
- if ::Mysql2::Client.const_defined?(:FOUND_ROWS)
51
- config_[:flags] = ::Mysql2::Client::FOUND_ROWS
52
- end
53
- client_ = ::Mysql2::Client.new(config_.symbolize_keys)
54
- options_ = [config_[:host], config_[:username], config_[:password], config_[:database], config_[:port], config_[:socket], 0]
55
- ConnectionAdapters::Mysql2SpatialAdapter.new(client_, logger, options_, config_)
56
- end
57
-
58
-
59
- end
60
-
61
-
62
- module ConnectionAdapters # :nodoc:
63
-
64
- class Mysql2SpatialAdapter < Mysql2Adapter # :nodoc:
65
-
66
-
67
- class SpatialColumn < ConnectionAdapters::Mysql2Column # :nodoc:
68
-
69
- include ::RGeo::ActiveRecord::MysqlCommon::ColumnMethods
70
-
71
- end
72
-
73
-
74
- include ::RGeo::ActiveRecord::MysqlCommon::AdapterMethods
75
-
76
-
77
- ADAPTER_NAME = 'Mysql2Spatial'.freeze
78
-
79
- NATIVE_DATABASE_TYPES = Mysql2Adapter::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"})
80
-
81
-
82
- def native_database_types
83
- NATIVE_DATABASE_TYPES
84
- end
85
-
86
-
87
- def adapter_name
88
- ADAPTER_NAME
89
- end
90
-
91
-
92
- def columns(table_name_, name_=nil)
93
- result_ = execute("SHOW FIELDS FROM #{quote_table_name(table_name_)}", :skip_logging)
94
- columns_ = []
95
- result_.each(:symbolize_keys => true, :as => :hash) do |field_|
96
- columns_ << SpatialColumn.new(field_[:Field], field_[:Default], field_[:Type], field_[:Null] == "YES")
97
- end
98
- columns_
99
- end
100
-
101
-
102
- def indexes(table_name_, name_=nil)
103
- indexes_ = []
104
- current_index_ = nil
105
- result_ = execute("SHOW KEYS FROM #{quote_table_name(table_name_)}", name_)
106
- result_.each(:symbolize_keys => true, :as => :hash) do |row_|
107
- if current_index_ != row_[:Key_name]
108
- next if row_[:Key_name] == 'PRIMARY' # skip the primary key
109
- current_index_ = row_[:Key_name]
110
- indexes_ << ::RGeo::ActiveRecord::Common::IndexDefinition.new(row_[:Table], row_[:Key_name], row_[:Non_unique] == 0, [], [], row_[:Index_type] == 'SPATIAL')
111
- end
112
- indexes_.last.columns << row_[:Column_name]
113
- indexes_.last.lengths << row_[:Sub_part]
114
- end
115
- indexes_
116
- end
117
-
118
-
119
- end
120
-
121
- end
122
-
123
-
124
- end
@@ -1,136 +0,0 @@
1
- # -----------------------------------------------------------------------------
2
- #
3
- # MysqlSpatial 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
- require 'rgeo/active_record/mysql_common'
38
- require 'active_record/connection_adapters/mysql_adapter'
39
-
40
-
41
- module ActiveRecord
42
-
43
- class Base
44
-
45
-
46
- # Create a mysqlspatial connection adapter
47
-
48
- def self.mysqlspatial_connection(config_)
49
- unless defined?(::Mysql)
50
- begin
51
- require 'mysql'
52
- rescue ::LoadError
53
- raise "!!! Missing the mysql gem. Add it to your Gemfile: gem 'mysql'"
54
- end
55
- unless defined?(::Mysql::Result) && ::Mysql::Result.method_defined?(:each_hash)
56
- raise "!!! Outdated mysql gem. Upgrade to 2.8.1 or later. In your Gemfile: gem 'mysql', '2.8.1'. Or use gem 'mysql2'"
57
- end
58
- end
59
- config_ = config_.symbolize_keys
60
- mysql_ = ::Mysql.init
61
- mysql_.ssl_set(config_[:sslkey], config_[:sslcert], config_[:sslca], config_[:sslcapath], config_[:sslcipher]) if config_[:sslca] || config_[:sslkey]
62
- default_flags_ = ::Mysql.const_defined?(:CLIENT_MULTI_RESULTS) ? ::Mysql::CLIENT_MULTI_RESULTS : 0
63
- default_flags_ |= ::Mysql::CLIENT_FOUND_ROWS if ::Mysql.const_defined?(:CLIENT_FOUND_ROWS)
64
- options_ = [config_[:host], config_[:username] ? config_[:username].to_s : 'root', config_[:password].to_s, config_[:database], config_[:port], config_[:socket], default_flags_]
65
- ConnectionAdapters::MysqlSpatialAdapter.new(mysql_, logger, options_, config_)
66
- end
67
-
68
-
69
- end
70
-
71
-
72
- module ConnectionAdapters # :nodoc:
73
-
74
- class MysqlSpatialAdapter < MysqlAdapter # :nodoc:
75
-
76
-
77
- class SpatialColumn < ConnectionAdapters::MysqlColumn # :nodoc:
78
-
79
- include ::RGeo::ActiveRecord::MysqlCommon::ColumnMethods
80
-
81
- end
82
-
83
-
84
- include ::RGeo::ActiveRecord::MysqlCommon::AdapterMethods
85
-
86
-
87
- ADAPTER_NAME = 'MysqlSpatial'.freeze
88
-
89
- NATIVE_DATABASE_TYPES = MysqlAdapter::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"})
90
-
91
-
92
- def native_database_types
93
- NATIVE_DATABASE_TYPES
94
- end
95
-
96
-
97
- def adapter_name
98
- ADAPTER_NAME
99
- end
100
-
101
-
102
- def columns(table_name_, name_=nil)
103
- result_ = execute("SHOW FIELDS FROM #{quote_table_name(table_name_)}", :skip_logging)
104
- columns_ = []
105
- result_.each do |field_|
106
- columns_ << SpatialColumn.new(field_[0], field_[4], field_[1], field_[2] == "YES")
107
- end
108
- result_.free
109
- columns_
110
- end
111
-
112
-
113
- def indexes(table_name_, name_=nil)
114
- indexes_ = []
115
- current_index_ = nil
116
- result_ = execute("SHOW KEYS FROM #{quote_table_name(table_name_)}", name_)
117
- result_.each do |row_|
118
- if current_index_ != row_[2]
119
- next if row_[2] == "PRIMARY" # skip the primary key
120
- current_index_ = row_[2]
121
- indexes_ << ::RGeo::ActiveRecord::Common::IndexDefinition.new(row_[0], row_[2], row_[1] == "0", [], [], row_[10] == 'SPATIAL')
122
- end
123
- indexes_.last.columns << row_[4]
124
- indexes_.last.lengths << row_[7]
125
- end
126
- result_.free
127
- indexes_
128
- end
129
-
130
-
131
- end
132
-
133
- end
134
-
135
-
136
- end
@@ -1,426 +0,0 @@
1
- # -----------------------------------------------------------------------------
2
- #
3
- # PostGIS 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
- require 'rgeo/active_record/common'
38
- require 'active_record/connection_adapters/postgresql_adapter'
39
-
40
-
41
- module ActiveRecord
42
-
43
- class Base
44
-
45
-
46
- # Create a postgis connection adapter.
47
-
48
-
49
- def self.postgis_connection(config_)
50
- require 'pg'
51
-
52
- config_ = config_.symbolize_keys
53
- host_ = config_[:host]
54
- port_ = config_[:port] || 5432
55
- username_ = config_[:username].to_s if config_[:username]
56
- password_ = config_[:password].to_s if config_[:password]
57
- if config_.has_key?(:database)
58
- database_ = config_[:database]
59
- else
60
- raise ::ArgumentError, "No database specified. Missing argument: database."
61
- end
62
-
63
- # The postgres drivers don't allow the creation of an unconnected PGconn object,
64
- # so just pass a nil connection object for the time being.
65
- ConnectionAdapters::PostGisAdapter.new(nil, logger, [host_, port_, nil, nil, database_, username_, password_], config_)
66
- end
67
-
68
-
69
- end
70
-
71
-
72
- module ConnectionAdapters # :nodoc:
73
-
74
-
75
- class PostGisAdapter < PostgreSQLAdapter # :nodoc:
76
-
77
-
78
- ADAPTER_NAME = 'PostGIS'.freeze
79
-
80
- @@native_database_types = nil
81
-
82
-
83
- def native_database_types
84
- @@native_database_types ||= super.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"})
85
- end
86
-
87
-
88
- def adapter_name
89
- ADAPTER_NAME
90
- end
91
-
92
-
93
- def postgis_lib_version
94
- unless defined?(@postgis_lib_version)
95
- @postgis_lib_version = select_value("SELECT PostGIS_Lib_Version()") rescue nil
96
- end
97
- @postgis_lib_version
98
- end
99
-
100
-
101
- def quote(value_, column_=nil)
102
- if ::RGeo::Feature::Geometry.check_type(value_)
103
- "'#{::RGeo::WKRep::WKBGenerator.new(:hex_format => true, :type_format => :ewkb, :emit_ewkb_srid => true).generate(value_)}'"
104
- else
105
- super
106
- end
107
- end
108
-
109
-
110
- def columns(table_name_, name_=nil) #:nodoc:
111
- table_name_ = table_name_.to_s
112
- spatial_info_ = spatial_column_info(table_name_)
113
- column_definitions(table_name_).collect do |name_, type_, default_, notnull_|
114
- SpatialColumn.new(name_, default_, type_, notnull_ == 'f', type_ =~ /geometry/i ? spatial_info_[name_] : nil)
115
- end
116
- end
117
-
118
-
119
- def create_table(table_name_, options_={})
120
- table_name_ = table_name_.to_s
121
- table_definition_ = SpatialTableDefinition.new(self)
122
- table_definition_.primary_key(options_[:primary_key] || ::ActiveRecord::Base.get_primary_key(table_name_.singularize)) unless options_[:id] == false
123
- yield table_definition_ if block_given?
124
- if options_[:force] && table_exists?(table_name_)
125
- drop_table(table_name_, options_)
126
- end
127
-
128
- create_sql_ = "CREATE#{' TEMPORARY' if options_[:temporary]} TABLE "
129
- create_sql_ << "#{quote_table_name(table_name_)} ("
130
- create_sql_ << table_definition_.to_sql
131
- create_sql_ << ") #{options_[:options]}"
132
- execute create_sql_
133
-
134
- table_definition_.non_geographic_spatial_columns.each do |col_|
135
- type_ = col_.type.to_s.gsub('_', '').upcase
136
- has_z_ = col_.has_z?
137
- has_m_ = col_.has_m?
138
- type_ = "#{type_}M" if has_m_ && !has_z_
139
- dimensions_ = 2
140
- dimensions_ += 1 if has_z_
141
- dimensions_ += 1 if has_m_
142
- execute("SELECT AddGeometryColumn('#{quote_string(table_name_)}', '#{quote_string(col_.name)}', #{col_.srid}, '#{quote_string(type_)}', #{dimensions_})")
143
- end
144
- end
145
-
146
-
147
- def drop_table(table_name_, options_={})
148
- execute("DELETE from geometry_columns where f_table_name='#{quote_string(table_name_.to_s)}'")
149
- super
150
- end
151
-
152
-
153
- def add_column(table_name_, column_name_, type_, options_={})
154
- table_name_ = table_name_.to_s
155
- if ::RGeo::ActiveRecord::GEOMETRY_TYPES.include?(type_.to_sym)
156
- type_ = type_.to_s.gsub('_', '').upcase
157
- has_z_ = options_[:has_z]
158
- has_m_ = options_[:has_m]
159
- srid_ = (options_[:srid] || 4326).to_i
160
- if options_[:geographic]
161
- type_ << 'Z' if has_z_
162
- type_ << 'M' if has_m_
163
- execute("ALTER TABLE #{quote_table_name(table_name_)} ADD COLUMN #{quote_column_name(column_name_)} GEOGRAPHY(#{type_},#{srid_})")
164
- change_column_default(table_name_, column_name_, options_[:default]) if options_include_default?(options_)
165
- change_column_null(table_name_, column_name_, false, options_[:default]) if options_[:null] == false
166
- else
167
- type_ = "#{type_}M" if has_m_ && !has_z_
168
- dimensions_ = 2
169
- dimensions_ += 1 if has_z_
170
- dimensions_ += 1 if has_m_
171
- execute("SELECT AddGeometryColumn('#{quote_string(table_name_)}', '#{quote_string(column_name_.to_s)}', #{srid_}, '#{quote_string(type_)}', #{dimensions_})")
172
- end
173
- else
174
- super
175
- end
176
- end
177
-
178
-
179
- def remove_column(table_name_, *column_names_)
180
- column_names_ = column_names_.flatten.map{ |n_| n_.to_s }
181
- spatial_info_ = spatial_column_info(table_name_)
182
- remaining_column_names_ = []
183
- column_names_.each do |name_|
184
- if spatial_info_.include?(name_)
185
- execute("SELECT DropGeometryColumn('#{quote_string(table_name_.to_s)}','#{quote_string(name_)}')")
186
- else
187
- remaining_column_names_ << name_.to_sym
188
- end
189
- end
190
- if remaining_column_names_.size > 0
191
- super(table_name_, *remaining_column_names_)
192
- end
193
- end
194
-
195
-
196
- def add_index(table_name_, column_name_, options_={})
197
- table_name_ = table_name_.to_s
198
- column_names_ = ::Array.wrap(column_name_)
199
- index_name_ = index_name(table_name_, :column => column_names_)
200
- gist_clause_ = ''
201
- index_type_ = ''
202
- if ::Hash === options_ # legacy support, since this param was a string
203
- index_type_ = 'UNIQUE' if options_[:unique]
204
- index_name_ = options_[:name].to_s if options_.key?(:name)
205
- gist_clause_ = 'USING GIST' if options_[:spatial]
206
- else
207
- index_type_ = options_
208
- end
209
- if index_name_.length > index_name_length
210
- raise ::ArgumentError, "Index name '#{index_name_}' on table '#{table_name_}' is too long; the limit is #{index_name_length} characters"
211
- end
212
- if index_name_exists?(table_name_, index_name_, false)
213
- raise ::ArgumentError, "Index name '#{index_name_}' on table '#{table_name_}' already exists"
214
- end
215
- quoted_column_names_ = quoted_columns_for_index(column_names_, options_).join(", ")
216
- execute "CREATE #{index_type_} INDEX #{quote_column_name(index_name_)} ON #{quote_table_name(table_name_)} #{gist_clause_} (#{quoted_column_names_})"
217
- end
218
-
219
-
220
- def spatial_column_info(table_name_)
221
- info_ = query("SELECT * FROM geometry_columns WHERE f_table_name='#{quote_string(table_name_.to_s)}'")
222
- result_ = {}
223
- info_.each do |row_|
224
- name_ = row_[3]
225
- type_ = row_[6]
226
- dimension_ = row_[4].to_i
227
- has_m_ = type_ =~ /m$/i ? true : false
228
- type_.sub!(/m$/, '')
229
- has_z_ = dimension_ > 3 || dimension_ == 3 && !has_m_
230
- result_[name_] = {
231
- :name => name_,
232
- :type => type_,
233
- :dimension => dimension_,
234
- :srid => row_[5].to_i,
235
- :has_z => has_z_,
236
- :has_m => has_m_,
237
- }
238
- end
239
- result_
240
- end
241
-
242
-
243
- class SpatialTableDefinition < ConnectionAdapters::TableDefinition # :nodoc:
244
-
245
- attr_reader :spatial_columns
246
-
247
- def initialize(base_)
248
- super
249
- end
250
-
251
- def column(name_, type_, options_={})
252
- super
253
- col_ = self[name_]
254
- if ::RGeo::ActiveRecord::GEOMETRY_TYPES.include?(col_.type.to_sym)
255
- col_.extend(GeometricColumnDefinitionMethods) unless col_.respond_to?(:geographic?)
256
- col_.set_geographic(options_[:geographic])
257
- col_.set_srid((options_[:srid] || 4326).to_i)
258
- col_.set_has_z(options_[:has_z])
259
- col_.set_has_m(options_[:has_m])
260
- end
261
- self
262
- end
263
-
264
- def to_sql
265
- @columns.find_all{ |c_| !c_.respond_to?(:geographic?) || c_.geographic? }.map{ |c_| c_.to_sql } * ', '
266
- end
267
-
268
- def non_geographic_spatial_columns
269
- @columns.find_all{ |c_| c_.respond_to?(:geographic?) && !c_.geographic? }
270
- end
271
-
272
- end
273
-
274
-
275
- module GeometricColumnDefinitionMethods # :nodoc:
276
-
277
- def geographic?
278
- defined?(@geographic) && @geographic
279
- end
280
-
281
- def srid
282
- defined?(@srid) ? @srid : 4326
283
- end
284
-
285
- def has_z?
286
- defined?(@has_z) && @has_z
287
- end
288
-
289
- def has_m?
290
- defined?(@has_m) && @has_m
291
- end
292
-
293
- def set_geographic(value_)
294
- @geographic = value_ ? true : false
295
- end
296
-
297
- def set_srid(value_)
298
- @srid = value_
299
- end
300
-
301
- def set_has_z(value_)
302
- @has_z = value_ ? true : false
303
- end
304
-
305
- def set_has_m(value_)
306
- @has_m = value_ ? true : false
307
- end
308
-
309
- def sql_type
310
- type_ = type.to_s.upcase.gsub('_', '')
311
- type_ << 'Z' if has_z?
312
- type_ << 'M' if has_m?
313
- "GEOGRAPHY(#{type_},#{srid})"
314
- end
315
-
316
- end
317
-
318
-
319
- class SpatialColumn < ConnectionAdapters::PostgreSQLColumn # :nodoc:
320
-
321
-
322
- def initialize(name_, default_, sql_type_=nil, null_=true, opts_=nil)
323
- super(name_, default_, sql_type_, null_)
324
- @geographic = sql_type_ =~ /^geography/ ? true : false
325
- if opts_
326
- @geometric_type = ::RGeo::ActiveRecord::Common.geometric_type_from_name(opts_[:type])
327
- @srid = opts_[:srid].to_i
328
- @has_z = opts_[:has_z]
329
- @has_m = opts_[:has_m]
330
- elsif @geographic
331
- if sql_type_ =~ /geography\((\w+[^,zm])(z?)(m?),(\d+)\)/i
332
- @has_z = $2.length > 0
333
- @has_m = $3.length > 0
334
- @srid = $4.to_i
335
- @geometric_type = ::RGeo::ActiveRecord::Common.geometric_type_from_name($1)
336
- else
337
- @geometric_type = ::RGeo::Feature::Geometry
338
- @srid = 4326
339
- @has_z = @has_m = false
340
- end
341
- else
342
- @geometric_type = @has_z = @has_m = nil
343
- @srid = 0
344
- end
345
- @ar_class = ::ActiveRecord::Base
346
- end
347
-
348
-
349
- def set_ar_class(val_)
350
- @ar_class = val_
351
- end
352
-
353
-
354
- attr_reader :srid
355
- attr_reader :geometric_type
356
- attr_reader :has_z
357
- attr_reader :has_m
358
-
359
-
360
- def spatial?
361
- type == :geometry
362
- end
363
-
364
-
365
- def geographic?
366
- @geographic
367
- end
368
-
369
-
370
- def klass
371
- type == :geometry ? ::RGeo::Feature::Geometry : super
372
- end
373
-
374
-
375
- def type_cast(value_)
376
- type == :geometry ? SpatialColumn.string_to_geometry(value_, @ar_class, @geographic, @srid, @has_z, @has_m) : super
377
- end
378
-
379
-
380
- def type_cast_code(var_name_)
381
- type == :geometry ? "::ActiveRecord::ConnectionAdapters::PostGisAdapter::SpatialColumn.string_to_geometry(#{var_name_}, self.class, #{@geographic ? 'true' : 'false'}, #{@srid.inspect}, #{@has_z ? 'true' : 'false'}, #{@has_m ? 'true' : 'false'})" : super
382
- end
383
-
384
-
385
- private
386
-
387
-
388
- def simplified_type(sql_type_)
389
- sql_type_ =~ /geography|geometry|point|linestring|polygon/i ? :geometry : super
390
- end
391
-
392
-
393
- def self.string_to_geometry(str_, ar_class_, geographic_, srid_, has_z_, has_m_)
394
- case str_
395
- when ::RGeo::Feature::Geometry
396
- str_
397
- when ::String
398
- if str_.length == 0
399
- nil
400
- else
401
- factory_ = ar_class_.rgeo_factory_generator.call(:srid => srid_, :has_z_coordinate => has_z_, :has_m_coordinate => has_m_, :geographic => geographic_)
402
- marker_ = str_[0,1]
403
- if marker_ == "\x00" || marker_ == "\x01"
404
- ::RGeo::WKRep::WKBParser.new(factory_, :support_ewkb => true).parse(str_) rescue nil
405
- elsif str_[0,4] =~ /[0-9a-fA-F]{4}/
406
- ::RGeo::WKRep::WKBParser.new(factory_, :support_ewkb => true).parse_hex(str_) rescue nil
407
- else
408
- ::RGeo::WKRep::WKTParser.new(factory_, :support_ewkt => true).parse(str_) rescue nil
409
- end
410
- end
411
- else
412
- nil
413
- end
414
- end
415
-
416
-
417
- end
418
-
419
-
420
- end
421
-
422
-
423
- end
424
-
425
-
426
- end