spatial_adapter 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +3 -0
  2. data/Gemfile +3 -0
  3. data/README.rdoc +30 -17
  4. data/Rakefile +11 -0
  5. data/init.rb +1 -0
  6. data/lib/spatial_adapter/base/mysql/adapter.rb +54 -0
  7. data/lib/spatial_adapter/base/mysql/spatial_column.rb +12 -0
  8. data/lib/spatial_adapter/base/mysql.rb +9 -0
  9. data/lib/spatial_adapter/common/schema_dumper.rb +12 -12
  10. data/lib/spatial_adapter/common/spatial_column.rb +4 -4
  11. data/lib/spatial_adapter/common/table_definition.rb +8 -10
  12. data/lib/spatial_adapter/common.rb +10 -0
  13. data/lib/spatial_adapter/jdbcmysql.rb +50 -0
  14. data/lib/spatial_adapter/mysql.rb +43 -85
  15. data/lib/spatial_adapter/mysql2.rb +39 -86
  16. data/lib/spatial_adapter/postgresql.rb +315 -324
  17. data/lib/spatial_adapter/version.rb +3 -0
  18. data/lib/spatial_adapter.rb +3 -7
  19. data/spatial_adapter.gemspec +39 -0
  20. data/spec/db/jdbcmysql_raw.rb +70 -0
  21. data/spec/db/mysql2_raw.rb +9 -9
  22. data/spec/db/mysql_raw.rb +9 -9
  23. data/spec/jdbcmysql_spec.rb +25 -0
  24. data/spec/mysql2_spec.rb +31 -0
  25. data/spec/mysql_spec.rb +17 -0
  26. data/spec/postgresql/connection_adapter_spec.rb +34 -39
  27. data/spec/postgresql/migration_spec.rb +51 -51
  28. data/spec/postgresql/models_spec.rb +37 -37
  29. data/spec/postgresql/schema_dumper_spec.rb +12 -12
  30. data/spec/postgresql_spec.rb +5 -0
  31. data/spec/{shared_examples.rb → shared/common_model_actions_spec.rb} +2 -2
  32. data/spec/shared/mysql_connection_adapter_spec.rb +110 -0
  33. data/spec/{mysql/migration_spec.rb → shared/mysql_migration_spec.rb} +17 -17
  34. data/spec/shared/mysql_models_spec.rb +58 -0
  35. data/spec/{mysql/schema_dumper_spec.rb → shared/mysql_schema_dumper_spec.rb} +24 -27
  36. data/spec/spec_helper.rb +25 -21
  37. metadata +131 -84
  38. data/VERSION +0 -1
  39. data/spec/README.txt +0 -22
  40. data/spec/mysql/connection_adapter_spec.rb +0 -106
  41. data/spec/mysql/models_spec.rb +0 -65
  42. data/spec/mysql2/connection_adapter_spec.rb +0 -106
  43. data/spec/mysql2/migration_spec.rb +0 -64
  44. data/spec/mysql2/models_spec.rb +0 -65
  45. data/spec/mysql2/schema_dumper_spec.rb +0 -56
@@ -1,388 +1,379 @@
1
1
  require 'spatial_adapter'
2
2
  require 'active_record/connection_adapters/postgresql_adapter'
3
3
 
4
- ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
5
- include SpatialAdapter
6
-
7
- def postgis_version
8
- begin
9
- select_value("SELECT postgis_full_version()").scan(/POSTGIS="([\d\.]*)"/)[0][0]
10
- rescue ActiveRecord::StatementInvalid
11
- nil
4
+ module ActiveRecord::ConnectionAdapters
5
+ class PostgreSQLAdapter
6
+ def postgis_version
7
+ begin
8
+ select_value("SELECT postgis_full_version()").scan(/POSTGIS="([\d\.]*)"/)[0][0]
9
+ rescue ActiveRecord::StatementInvalid
10
+ nil
11
+ end
12
12
  end
13
- end
14
-
15
- def postgis_major_version
16
- version = postgis_version
17
- version ? version.scan(/^(\d)\.\d\.\d$/)[0][0].to_i : nil
18
- end
19
-
20
- def postgis_minor_version
21
- version = postgis_version
22
- version ? version.scan(/^\d\.(\d)\.\d$/)[0][0].to_i : nil
23
- end
24
-
25
- def spatial?
26
- !postgis_version.nil?
27
- end
28
-
29
- def supports_geographic?
30
- postgis_major_version > 1 || (postgis_major_version == 1 && postgis_minor_version >= 5)
31
- end
32
-
33
- alias :original_native_database_types :native_database_types
34
- def native_database_types
35
- original_native_database_types.merge!(geometry_data_types)
36
- end
37
13
 
38
- alias :original_quote :quote
39
- #Redefines the quote method to add behaviour for when a Geometry is encountered
40
- def quote(value, column = nil)
41
- if value.kind_of?(GeoRuby::SimpleFeatures::Geometry)
42
- "'#{value.as_hex_ewkb}'"
43
- else
44
- original_quote(value,column)
14
+ def postgis_major_version
15
+ version = postgis_version
16
+ version ? version.scan(/^(\d)\.\d\.\d$/)[0][0].to_i : nil
17
+ end
18
+
19
+ def postgis_minor_version
20
+ version = postgis_version
21
+ version ? version.scan(/^\d\.(\d)\.\d$/)[0][0].to_i : nil
22
+ end
23
+
24
+ def spatial?
25
+ !postgis_version.nil?
26
+ end
27
+
28
+ def supports_geographic?
29
+ postgis_major_version > 1 || (postgis_major_version == 1 && postgis_minor_version >= 5)
30
+ end
31
+
32
+ alias :original_native_database_types :native_database_types
33
+ def native_database_types
34
+ original_native_database_types.merge!(SpatialAdapter.geometry_data_types)
35
+ end
36
+
37
+ alias :original_quote :quote
38
+ #Redefines the quote method to add behaviour for when a Geometry is encountered
39
+ def quote(value, column = nil)
40
+ if value.kind_of?(GeoRuby::SimpleFeatures::Geometry)
41
+ "'#{value.as_hex_ewkb}'"
42
+ else
43
+ original_quote(value,column)
44
+ end
45
45
  end
46
- end
47
46
 
48
- def columns(table_name, name = nil) #:nodoc:
49
- raw_geom_infos = column_spatial_info(table_name)
50
-
51
- column_definitions(table_name).collect do |name, type, default, notnull|
52
- case type
53
- when /geography/i
54
- ActiveRecord::ConnectionAdapters::SpatialPostgreSQLColumn.create_from_geography(name, default, type, notnull == 'f')
55
- when /geometry/i
56
- raw_geom_info = raw_geom_infos[name]
57
- if raw_geom_info.nil?
58
- # This column isn't in the geometry_columns table, so we don't know anything else about it
59
- ActiveRecord::ConnectionAdapters::SpatialPostgreSQLColumn.create_simplified(name, default, notnull == "f")
47
+ def columns(table_name, name = nil) #:nodoc:
48
+ raw_geom_infos = column_spatial_info(table_name)
49
+
50
+ column_definitions(table_name).collect do |name, type, default, notnull|
51
+ case type
52
+ when /geography/i
53
+ ActiveRecord::ConnectionAdapters::SpatialPostgreSQLColumn.create_from_geography(name, default, type, notnull == 'f')
54
+ when /geometry/i
55
+ raw_geom_info = raw_geom_infos[name]
56
+ if raw_geom_info.nil?
57
+ # This column isn't in the geometry_columns table, so we don't know anything else about it
58
+ ActiveRecord::ConnectionAdapters::SpatialPostgreSQLColumn.create_simplified(name, default, notnull == "f")
59
+ else
60
+ ActiveRecord::ConnectionAdapters::SpatialPostgreSQLColumn.new(name, default, raw_geom_info.type, notnull == "f", raw_geom_info.srid, raw_geom_info.with_z, raw_geom_info.with_m)
61
+ end
60
62
  else
61
- ActiveRecord::ConnectionAdapters::SpatialPostgreSQLColumn.new(name, default, raw_geom_info.type, notnull == "f", raw_geom_info.srid, raw_geom_info.with_z, raw_geom_info.with_m)
63
+ ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new(name, default, type, notnull == "f")
62
64
  end
63
- else
64
- ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new(name, default, type, notnull == "f")
65
65
  end
66
66
  end
67
- end
68
67
 
69
- def create_table(table_name, options = {})
70
- # Using the subclassed table definition
71
- table_definition = ActiveRecord::ConnectionAdapters::PostgreSQLTableDefinition.new(self)
72
- table_definition.primary_key(options[:primary_key] || ActiveRecord::Base.get_primary_key(table_name.to_s.singularize)) unless options[:id] == false
68
+ def create_table(table_name, options = {})
69
+ # Using the subclassed table definition
70
+ table_definition = ActiveRecord::ConnectionAdapters::PostgreSQLTableDefinition.new(self)
71
+ table_definition.primary_key(options[:primary_key] || ActiveRecord::Base.get_primary_key(table_name.to_s.singularize)) unless options[:id] == false
73
72
 
74
- yield table_definition if block_given?
73
+ yield table_definition if block_given?
75
74
 
76
- if options[:force] && table_exists?(table_name)
77
- drop_table(table_name, options)
78
- end
75
+ if options[:force] && table_exists?(table_name)
76
+ drop_table(table_name, options)
77
+ end
79
78
 
80
- create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
81
- create_sql << "#{quote_table_name(table_name)} ("
82
- create_sql << table_definition.to_sql
83
- create_sql << ") #{options[:options]}"
79
+ create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
80
+ create_sql << "#{quote_table_name(table_name)} ("
81
+ create_sql << table_definition.to_sql
82
+ create_sql << ") #{options[:options]}"
84
83
 
85
- # This is the additional portion for PostGIS
86
- unless table_definition.geom_columns.nil?
87
- table_definition.geom_columns.each do |geom_column|
88
- geom_column.table_name = table_name
89
- create_sql << "; " + geom_column.to_sql
84
+ # This is the additional portion for PostGIS
85
+ unless table_definition.geom_columns.nil?
86
+ table_definition.geom_columns.each do |geom_column|
87
+ geom_column.table_name = table_name
88
+ create_sql << "; " + geom_column.to_sql
89
+ end
90
90
  end
91
- end
92
91
 
93
- execute create_sql
94
- end
92
+ execute create_sql
93
+ end
95
94
 
96
- alias :original_remove_column :remove_column
97
- def remove_column(table_name, *column_names)
98
- column_names = column_names.flatten
99
- columns(table_name).each do |col|
100
- if column_names.include?(col.name.to_sym)
101
- # Geometry columns have to be removed using DropGeometryColumn
102
- if col.is_a?(SpatialColumn) && col.spatial? && !col.geographic?
103
- execute "SELECT DropGeometryColumn('#{table_name}','#{col.name}')"
104
- else
105
- original_remove_column(table_name, col.name)
95
+ alias :original_remove_column :remove_column
96
+ def remove_column(table_name, *column_names)
97
+ column_names = column_names.flatten
98
+ columns(table_name).each do |col|
99
+ if column_names.include?(col.name.to_sym)
100
+ # Geometry columns have to be removed using DropGeometryColumn
101
+ if col.is_a?(::SpatialAdapter::SpatialColumn) && col.spatial? && !col.geographic?
102
+ execute "SELECT DropGeometryColumn('#{table_name}','#{col.name}')"
103
+ else
104
+ original_remove_column(table_name, col.name)
105
+ end
106
106
  end
107
107
  end
108
108
  end
109
- end
110
-
111
- alias :original_add_column :add_column
112
- def add_column(table_name, column_name, type, options = {})
113
- unless geometry_data_types[type].nil?
114
- geom_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumnDefinition.new(self, column_name, type, nil, nil, options[:null], options[:srid] || -1 , options[:with_z] || false , options[:with_m] || false, options[:geographic] || false)
115
- if geom_column.geographic
116
- default = options[:default]
117
- notnull = options[:null] == false
118
-
119
- execute("ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{geom_column.to_sql}")
120
-
121
- change_column_default(table_name, column_name, default) if options_include_default?(options)
122
- change_column_null(table_name, column_name, false, default) if notnull
109
+
110
+ alias :original_add_column :add_column
111
+ def add_column(table_name, column_name, type, options = {})
112
+ unless SpatialAdapter.geometry_data_types[type].nil?
113
+ geom_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumnDefinition.new(self, column_name, type, nil, nil, options[:null], options[:srid] || -1 , options[:with_z] || false , options[:with_m] || false, options[:geographic] || false)
114
+ if geom_column.geographic
115
+ default = options[:default]
116
+ notnull = options[:null] == false
117
+
118
+ execute("ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{geom_column.to_sql}")
119
+
120
+ change_column_default(table_name, column_name, default) if options_include_default?(options)
121
+ change_column_null(table_name, column_name, false, default) if notnull
122
+ else
123
+ geom_column.table_name = table_name
124
+ execute geom_column.to_sql
125
+ end
123
126
  else
124
- geom_column.table_name = table_name
125
- execute geom_column.to_sql
127
+ original_add_column(table_name, column_name, type, options)
126
128
  end
127
- else
128
- original_add_column(table_name, column_name, type, options)
129
129
  end
130
- end
131
130
 
132
- # Adds an index to a column.
133
- def add_index(table_name, column_name, options = {})
134
- column_names = Array(column_name)
135
- index_name = index_name(table_name, :column => column_names)
136
-
137
- if Hash === options # legacy support, since this param was a string
138
- index_type = options[:unique] ? "UNIQUE" : ""
139
- index_name = options[:name] || index_name
140
- index_method = options[:spatial] ? 'USING GIST' : ""
141
- else
142
- index_type = options
131
+ # Adds an index to a column.
132
+ def add_index(table_name, column_name, options = {})
133
+ column_names = Array(column_name)
134
+ index_name = index_name(table_name, :column => column_names)
135
+
136
+ if Hash === options # legacy support, since this param was a string
137
+ index_type = options[:unique] ? "UNIQUE" : ""
138
+ index_name = options[:name] || index_name
139
+ index_method = options[:spatial] ? 'USING GIST' : ""
140
+ else
141
+ index_type = options
142
+ end
143
+ quoted_column_names = column_names.map { |e| quote_column_name(e) }.join(", ")
144
+ execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{index_method} (#{quoted_column_names})"
143
145
  end
144
- quoted_column_names = column_names.map { |e| quote_column_name(e) }.join(", ")
145
- execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{index_method} (#{quoted_column_names})"
146
- end
147
146
 
148
- # Returns the list of all indexes for a table.
149
- #
150
- # This is a full replacement for the ActiveRecord method and as a result
151
- # has a higher probability of breaking in future releases.
152
- def indexes(table_name, name = nil)
153
- schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
154
-
155
- # Changed from upstread: link to pg_am to grab the index type (e.g. "gist")
156
- result = query(<<-SQL, name)
157
- SELECT distinct i.relname, d.indisunique, d.indkey, t.oid, am.amname
158
- FROM pg_class t, pg_class i, pg_index d, pg_attribute a, pg_am am
159
- WHERE i.relkind = 'i'
160
- AND d.indexrelid = i.oid
161
- AND d.indisprimary = 'f'
162
- AND t.oid = d.indrelid
163
- AND t.relname = '#{table_name}'
164
- AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN (#{schemas}) )
165
- AND i.relam = am.oid
166
- AND a.attrelid = t.oid
167
- ORDER BY i.relname
168
- SQL
169
-
170
-
171
- indexes = []
172
-
173
- indexes = result.map do |row|
174
- index_name = row[0]
175
- unique = row[1] == 't'
176
- indkey = row[2].split(" ")
177
- oid = row[3]
178
- indtype = row[4]
179
-
180
- # Changed from upstream: need to get the column types to test for spatial indexes
181
- columns = query(<<-SQL, "Columns for index #{row[0]} on #{table_name}").inject({}) {|attlist, r| attlist[r[1]] = [r[0], r[2]]; attlist}
182
- SELECT a.attname, a.attnum, t.typname
183
- FROM pg_attribute a, pg_type t
184
- WHERE a.attrelid = #{oid}
185
- AND a.attnum IN (#{indkey.join(",")})
186
- AND a.atttypid = t.oid
147
+ # Returns the list of all indexes for a table.
148
+ #
149
+ # This is a full replacement for the ActiveRecord method and as a result
150
+ # has a higher probability of breaking in future releases.
151
+ def indexes(table_name, name = nil)
152
+ schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
153
+
154
+ # Changed from upstread: link to pg_am to grab the index type (e.g. "gist")
155
+ result = query(<<-SQL, name)
156
+ SELECT distinct i.relname, d.indisunique, d.indkey, t.oid, am.amname
157
+ FROM pg_class t, pg_class i, pg_index d, pg_attribute a, pg_am am
158
+ WHERE i.relkind = 'i'
159
+ AND d.indexrelid = i.oid
160
+ AND d.indisprimary = 'f'
161
+ AND t.oid = d.indrelid
162
+ AND t.relname = '#{table_name}'
163
+ AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN (#{schemas}) )
164
+ AND i.relam = am.oid
165
+ AND a.attrelid = t.oid
166
+ ORDER BY i.relname
187
167
  SQL
188
168
 
189
- # Only GiST indexes on spatial columns denote a spatial index
190
- spatial = indtype == 'gist' && columns.size == 1 && (columns.values.first[1] == 'geometry' || columns.values.first[1] == 'geography')
191
169
 
192
- column_names = indkey.map {|attnum| columns[attnum] ? columns[attnum][0] : nil }
193
- ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, index_name, unique, column_names, spatial)
194
- end
170
+ indexes = []
195
171
 
196
- indexes
197
- end
172
+ indexes = result.map do |row|
173
+ index_name = row[0]
174
+ unique = row[1] == 't'
175
+ indkey = row[2].split(" ")
176
+ oid = row[3]
177
+ indtype = row[4]
198
178
 
199
- def disable_referential_integrity(&block) #:nodoc:
200
- if supports_disable_referential_integrity?() then
201
- execute(tables_without_postgis.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
202
- end
203
- yield
204
- ensure
205
- if supports_disable_referential_integrity?() then
206
- execute(tables_without_postgis.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
179
+ # Changed from upstream: need to get the column types to test for spatial indexes
180
+ columns = query(<<-SQL, "Columns for index #{row[0]} on #{table_name}").inject({}) {|attlist, r| attlist[r[1]] = [r[0], r[2]]; attlist}
181
+ SELECT a.attname, a.attnum, t.typname
182
+ FROM pg_attribute a, pg_type t
183
+ WHERE a.attrelid = #{oid}
184
+ AND a.attnum IN (#{indkey.join(",")})
185
+ AND a.atttypid = t.oid
186
+ SQL
187
+
188
+ # Only GiST indexes on spatial columns denote a spatial index
189
+ spatial = indtype == 'gist' && columns.size == 1 && (columns.values.first[1] == 'geometry' || columns.values.first[1] == 'geography')
190
+
191
+ column_names = indkey.map {|attnum| columns[attnum] ? columns[attnum][0] : nil }
192
+ ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, index_name, unique, column_names, spatial)
193
+ end
194
+
195
+ indexes
207
196
  end
208
- end
209
197
 
210
- private
211
-
212
- def tables_without_postgis
213
- tables - %w{ geometry_columns spatial_ref_sys }
214
- end
215
-
216
- def column_spatial_info(table_name)
217
- constr = query("SELECT * FROM geometry_columns WHERE f_table_name = '#{table_name}'")
218
-
219
- raw_geom_infos = {}
220
- constr.each do |constr_def_a|
221
- raw_geom_infos[constr_def_a[3]] ||= SpatialAdapter::RawGeomInfo.new
222
- raw_geom_infos[constr_def_a[3]].type = constr_def_a[6]
223
- raw_geom_infos[constr_def_a[3]].dimension = constr_def_a[4].to_i
224
- raw_geom_infos[constr_def_a[3]].srid = constr_def_a[5].to_i
225
-
226
- if raw_geom_infos[constr_def_a[3]].type[-1] == ?M
227
- raw_geom_infos[constr_def_a[3]].with_m = true
228
- raw_geom_infos[constr_def_a[3]].type.chop!
229
- else
230
- raw_geom_infos[constr_def_a[3]].with_m = false
198
+ def disable_referential_integrity(&block) #:nodoc:
199
+ if supports_disable_referential_integrity?() then
200
+ execute(tables_without_postgis.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
201
+ end
202
+ yield
203
+ ensure
204
+ if supports_disable_referential_integrity?() then
205
+ execute(tables_without_postgis.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
231
206
  end
232
207
  end
233
208
 
234
- raw_geom_infos.each_value do |raw_geom_info|
235
- #check the presence of z and m
236
- raw_geom_info.convert!
209
+ private
210
+
211
+ def tables_without_postgis
212
+ tables - %w{ geometry_columns spatial_ref_sys }
237
213
  end
238
214
 
239
- raw_geom_infos
215
+ def column_spatial_info(table_name)
216
+ constr = query("SELECT * FROM geometry_columns WHERE f_table_name = '#{table_name}'")
240
217
 
241
- end
242
- end
218
+ raw_geom_infos = {}
219
+ constr.each do |constr_def_a|
220
+ raw_geom_infos[constr_def_a[3]] ||= SpatialAdapter::RawGeomInfo.new
221
+ raw_geom_infos[constr_def_a[3]].type = constr_def_a[6]
222
+ raw_geom_infos[constr_def_a[3]].dimension = constr_def_a[4].to_i
223
+ raw_geom_infos[constr_def_a[3]].srid = constr_def_a[5].to_i
243
224
 
244
- module ActiveRecord
245
- module ConnectionAdapters
246
- class PostgreSQLTableDefinition < TableDefinition
247
- attr_reader :geom_columns
248
-
249
- def column(name, type, options = {})
250
- unless (@base.geometry_data_types[type.to_sym].nil? or
251
- (options[:create_using_addgeometrycolumn] == false))
252
-
253
- column = self[name] || PostgreSQLColumnDefinition.new(@base, name, type)
254
- column.null = options[:null]
255
- column.srid = options[:srid] || -1
256
- column.with_z = options[:with_z] || false
257
- column.with_m = options[:with_m] || false
258
- column.geographic = options[:geographic] || false
259
-
260
- if column.geographic
261
- @columns << column unless @columns.include? column
262
- else
263
- # Hold this column for later
264
- @geom_columns ||= []
265
- @geom_columns << column
266
- end
267
- self
225
+ if raw_geom_infos[constr_def_a[3]].type[-1] == ?M
226
+ raw_geom_infos[constr_def_a[3]].with_m = true
227
+ raw_geom_infos[constr_def_a[3]].type.chop!
268
228
  else
269
- super(name, type, options)
229
+ raw_geom_infos[constr_def_a[3]].with_m = false
270
230
  end
271
- end
272
- end
231
+ end
273
232
 
274
- class PostgreSQLColumnDefinition < ColumnDefinition
275
- attr_accessor :table_name
276
- attr_accessor :srid, :with_z, :with_m, :geographic
277
- attr_reader :spatial
278
-
279
- def initialize(base = nil, name = nil, type=nil, limit=nil, default=nil, null=nil, srid=-1, with_z=false, with_m=false, geographic=false)
280
- super(base, name, type, limit, default, null)
281
- @table_name = nil
282
- @spatial = true
283
- @srid = srid
284
- @with_z = with_z
285
- @with_m = with_m
286
- @geographic = geographic
233
+ raw_geom_infos.each_value do |raw_geom_info|
234
+ #check the presence of z and m
235
+ raw_geom_info.convert!
287
236
  end
288
-
289
- def sql_type
290
- if geographic
291
- type_sql = base.geometry_data_types[type.to_sym][:name]
292
- type_sql += "Z" if with_z
293
- type_sql += "M" if with_m
294
- # SRID is not yet supported (defaults to 4326)
295
- #type_sql += ", #{srid}" if (srid && srid != -1)
296
- type_sql = "geography(#{type_sql})"
297
- type_sql
237
+
238
+ raw_geom_infos
239
+ end
240
+ end
241
+
242
+ class PostgreSQLTableDefinition < TableDefinition
243
+ attr_reader :geom_columns
244
+
245
+ def column(name, type, options = {})
246
+ unless (SpatialAdapter.geometry_data_types[type.to_sym].nil? or
247
+ (options[:create_using_addgeometrycolumn] == false))
248
+
249
+ column = self[name] || PostgreSQLColumnDefinition.new(@base, name, type)
250
+ column.null = options[:null]
251
+ column.srid = options[:srid] || -1
252
+ column.with_z = options[:with_z] || false
253
+ column.with_m = options[:with_m] || false
254
+ column.geographic = options[:geographic] || false
255
+
256
+ if column.geographic
257
+ @columns << column unless @columns.include? column
298
258
  else
299
- super
259
+ # Hold this column for later
260
+ @geom_columns ||= []
261
+ @geom_columns << column
300
262
  end
263
+ self
264
+ else
265
+ super(name, type, options)
301
266
  end
302
-
303
- def to_sql
304
- if spatial && !geographic
305
- type_sql = base.geometry_data_types[type.to_sym][:name]
306
- type_sql += "M" if with_m and !with_z
307
- if with_m and with_z
308
- dimension = 4
309
- elsif with_m or with_z
310
- dimension = 3
311
- else
312
- dimension = 2
313
- end
314
-
315
- column_sql = "SELECT AddGeometryColumn('#{table_name}','#{name}',#{srid},'#{type_sql}',#{dimension})"
316
- column_sql += ";ALTER TABLE #{table_name} ALTER #{name} SET NOT NULL" if null == false
317
- column_sql
267
+ end
268
+ end
269
+
270
+ class PostgreSQLColumnDefinition < ColumnDefinition
271
+ attr_accessor :table_name
272
+ attr_accessor :srid, :with_z, :with_m, :geographic
273
+ attr_reader :spatial
274
+
275
+ def initialize(base = nil, name = nil, type=nil, limit=nil, default=nil, null=nil, srid=-1, with_z=false, with_m=false, geographic=false)
276
+ super(base, name, type, limit, default, null)
277
+ @table_name = nil
278
+ @spatial = true
279
+ @srid = srid
280
+ @with_z = with_z
281
+ @with_m = with_m
282
+ @geographic = geographic
283
+ end
284
+
285
+ def sql_type
286
+ if geographic
287
+ type_sql = SpatialAdapter.geometry_data_types[type.to_sym][:name]
288
+ type_sql += "Z" if with_z
289
+ type_sql += "M" if with_m
290
+ # SRID is not yet supported (defaults to 4326)
291
+ #type_sql += ", #{srid}" if (srid && srid != -1)
292
+ type_sql = "geography(#{type_sql})"
293
+ type_sql
294
+ else
295
+ super
296
+ end
297
+ end
298
+
299
+ def to_sql
300
+ if spatial && !geographic
301
+ type_sql = SpatialAdapter.geometry_data_types[type.to_sym][:name]
302
+ type_sql += "M" if with_m and !with_z
303
+ if with_m and with_z
304
+ dimension = 4
305
+ elsif with_m or with_z
306
+ dimension = 3
318
307
  else
319
- super
308
+ dimension = 2
320
309
  end
310
+
311
+ column_sql = "SELECT AddGeometryColumn('#{table_name}','#{name}',#{srid},'#{type_sql}',#{dimension})"
312
+ column_sql += ";ALTER TABLE #{table_name} ALTER #{name} SET NOT NULL" if null == false
313
+ column_sql
314
+ else
315
+ super
321
316
  end
322
317
  end
323
318
  end
324
- end
325
319
 
326
- module ActiveRecord
327
- module ConnectionAdapters
328
- class SpatialPostgreSQLColumn < PostgreSQLColumn
329
- include SpatialAdapter::SpatialColumn
320
+ class SpatialPostgreSQLColumn < PostgreSQLColumn
321
+ include SpatialAdapter::SpatialColumn
330
322
 
331
- def initialize(name, default, sql_type = nil, null = true, srid=-1, with_z=false, with_m=false, geographic = false)
332
- super(name, default, sql_type, null, srid, with_z, with_m)
333
- @geographic = geographic
334
- end
323
+ def initialize(name, default, sql_type = nil, null = true, srid=-1, with_z=false, with_m=false, geographic = false)
324
+ super(name, default, sql_type, null, srid, with_z, with_m)
325
+ @geographic = geographic
326
+ end
335
327
 
336
- def geographic?
337
- @geographic
338
- end
339
-
340
- #Transforms a string to a geometry. PostGIS returns a HewEWKB string.
341
- def self.string_to_geometry(string)
342
- return string unless string.is_a?(String)
343
- GeoRuby::SimpleFeatures::Geometry.from_hex_ewkb(string) rescue nil
344
- end
328
+ def geographic?
329
+ @geographic
330
+ end
345
331
 
346
- def self.create_simplified(name, default, null = true)
347
- new(name, default, "geometry", null)
348
- end
349
-
350
- def self.create_from_geography(name, default, sql_type, null = true)
351
- params = extract_geography_params(sql_type)
352
- new(name, default, sql_type, null, params[:srid], params[:with_z], params[:with_m], true)
353
- end
354
-
355
- private
356
-
357
- # Add detection of PostGIS-specific geography columns
358
- def geometry_simplified_type(sql_type)
359
- case sql_type
360
- when /geography\(point/i then :point
361
- when /geography\(linestring/i then :line_string
362
- when /geography\(polygon/i then :polygon
363
- when /geography\(multipoint/i then :multi_point
364
- when /geography\(multilinestring/i then :multi_line_string
365
- when /geography\(multipolygon/i then :multi_polygon
366
- when /geography\(geometrycollection/i then :geometry_collection
367
- when /geography/i then :geometry
368
- else
369
- super
370
- end
332
+ #Transforms a string to a geometry. PostGIS returns a HewEWKB string.
333
+ def self.string_to_geometry(string)
334
+ return string unless string.is_a?(String)
335
+ GeoRuby::SimpleFeatures::Geometry.from_hex_ewkb(string) rescue nil
336
+ end
337
+
338
+ def self.create_simplified(name, default, null = true)
339
+ new(name, default, "geometry", null)
340
+ end
341
+
342
+ def self.create_from_geography(name, default, sql_type, null = true)
343
+ params = extract_geography_params(sql_type)
344
+ new(name, default, sql_type, null, params[:srid], params[:with_z], params[:with_m], true)
345
+ end
346
+
347
+ private
348
+
349
+ # Add detection of PostGIS-specific geography columns
350
+ def geometry_simplified_type(sql_type)
351
+ case sql_type
352
+ when /geography\(point/i then :point
353
+ when /geography\(linestring/i then :line_string
354
+ when /geography\(polygon/i then :polygon
355
+ when /geography\(multipoint/i then :multi_point
356
+ when /geography\(multilinestring/i then :multi_line_string
357
+ when /geography\(multipolygon/i then :multi_polygon
358
+ when /geography\(geometrycollection/i then :geometry_collection
359
+ when /geography/i then :geometry
360
+ else
361
+ super
371
362
  end
363
+ end
372
364
 
373
- def self.extract_geography_params(sql_type)
374
- params = {
375
- :srid => 0,
376
- :with_z => false,
377
- :with_m => false
378
- }
379
- if sql_type =~ /geography(?:\((?:\w+?)(Z)?(M)?(?:,(\d+))?\))?/i
380
- params[:with_z] = $1 == 'Z'
381
- params[:with_m] = $2 == 'M'
382
- params[:srid] = $3.to_i
383
- end
384
- params
365
+ def self.extract_geography_params(sql_type)
366
+ params = {
367
+ :srid => 0,
368
+ :with_z => false,
369
+ :with_m => false
370
+ }
371
+ if sql_type =~ /geography(?:\((?:\w+?)(Z)?(M)?(?:,(\d+))?\))?/i
372
+ params[:with_z] = $1 == 'Z'
373
+ params[:with_m] = $2 == 'M'
374
+ params[:srid] = $3.to_i
385
375
  end
376
+ params
386
377
  end
387
378
  end
388
379
  end