schema_plus 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -51,6 +51,12 @@ module SchemaPlus
51
51
  :update
52
52
  end
53
53
  end
54
+
55
+ # The default as_jon includes all instance variables. but
56
+ # @connection can't be dumped (it contains circular references)
57
+ def as_json(options=nil)
58
+ instance_values.except "connection"
59
+ end
54
60
  end
55
61
  end
56
62
  end
@@ -9,6 +9,10 @@ module SchemaPlus
9
9
  # :set_null
10
10
  # :set_default
11
11
  # :no_action
12
+ #
13
+ # The deferrable attribute can take on the following values:
14
+ # true
15
+ # :initially_deferred
12
16
  class ForeignKeyDefinition
13
17
 
14
18
  # The name of the foreign key constraint
@@ -65,9 +69,9 @@ module SchemaPlus
65
69
  dump = (opts[:inline] ? " t.foreign_key" : "add_foreign_key #{table_name.inspect},")
66
70
  dump << " [#{Array(column_names).collect{ |name| name.inspect }.join(', ')}]"
67
71
  dump << ", #{references_table_name.inspect}, [#{Array(references_column_names).collect{ |name| name.inspect }.join(', ')}]"
68
- dump << ", :on_update => :#{on_update}" if on_update
69
- dump << ", :on_delete => :#{on_delete}" if on_delete
70
- dump << ", :deferrable => #{deferrable}" if deferrable
72
+ dump << ", :on_update => #{on_update.inspect}" if on_update
73
+ dump << ", :on_delete => #{on_delete.inspect}" if on_delete
74
+ dump << ", :deferrable => #{deferrable.inspect}" if deferrable
71
75
  dump << ", :name => #{name.inspect}" if name
72
76
  dump << "\n"
73
77
  dump
@@ -79,6 +83,7 @@ module SchemaPlus
79
83
  sql << " ON UPDATE #{ACTIONS[on_update]}" if on_update
80
84
  sql << " ON DELETE #{ACTIONS[on_delete]}" if on_delete
81
85
  sql << " DEFERRABLE" if deferrable
86
+ sql << " INITIALLY DEFERRED" if deferrable == :initially_deferred
82
87
  sql
83
88
  end
84
89
 
@@ -107,11 +112,16 @@ module SchemaPlus
107
112
  end
108
113
 
109
114
  def self.default_name(table_name, column_names)
110
- "fk_#{table_name}_#{Array.wrap(column_names).join('_and_')}"
115
+ "fk_#{fixup_schema_name(table_name)}_#{Array.wrap(column_names).join('_and_')}"
111
116
  end
112
117
 
113
118
  def self.auto_index_name(table_name, column_name)
114
- "fk__#{table_name}_#{Array.wrap(column_name).join('_and_')}"
119
+ "fk__#{fixup_schema_name(table_name)}_#{Array.wrap(column_name).join('_and_')}"
120
+ end
121
+
122
+ def self.fixup_schema_name(table_name)
123
+ # replace . with _
124
+ table_name.to_s.gsub(/[.]/, '_')
115
125
  end
116
126
 
117
127
  end
@@ -47,6 +47,12 @@ module SchemaPlus
47
47
  exec_stmt_without_schema_plus(sql, name, binds, &block)
48
48
  end
49
49
 
50
+ # implement cascade by removing foreign keys
51
+ def drop_table(name, options={})
52
+ reverse_foreign_keys(name).each{ |foreign_key| remove_foreign_key(foreign_key.table_name, foreign_key.name) } if options[:cascade]
53
+ super
54
+ end
55
+
50
56
  def remove_foreign_key(table_name, foreign_key_name, options = {})
51
57
  execute "ALTER TABLE #{quote_table_name(table_name)} DROP FOREIGN KEY #{foreign_key_name}"
52
58
  end
@@ -54,6 +60,9 @@ module SchemaPlus
54
60
  def foreign_keys(table_name, name = nil)
55
61
  results = execute("SHOW CREATE TABLE #{quote_table_name(table_name)}", name)
56
62
 
63
+ table_name = table_name.to_s
64
+ namespace_prefix = table_namespace_prefix(table_name)
65
+
57
66
  foreign_keys = []
58
67
 
59
68
  results.each do |row|
@@ -62,6 +71,7 @@ module SchemaPlus
62
71
  name = $1
63
72
  column_names = $2
64
73
  references_table_name = $3
74
+ references_table_name = namespace_prefix + references_table_name if table_namespace_prefix(references_table_name).blank?
65
75
  references_column_names = $4
66
76
  on_update = $8
67
77
  on_delete = $6
@@ -69,7 +79,7 @@ module SchemaPlus
69
79
  on_delete = on_delete ? on_delete.downcase.gsub(' ', '_').to_sym : :restrict
70
80
 
71
81
  foreign_keys << ForeignKeyDefinition.new(name,
72
- table_name, column_names.gsub('`', '').split(', '),
82
+ namespace_prefix + table_name, column_names.gsub('`', '').split(', '),
73
83
  references_table_name, references_column_names.gsub('`', '').split(', '),
74
84
  on_update, on_delete)
75
85
  end
@@ -83,17 +93,23 @@ module SchemaPlus
83
93
  results = execute(<<-SQL, name)
84
94
  SELECT constraint_name, table_name, column_name, referenced_table_name, referenced_column_name
85
95
  FROM information_schema.key_column_usage
86
- WHERE table_schema = SCHEMA()
96
+ WHERE table_schema = #{table_schema_sql(table_name)}
87
97
  AND referenced_table_schema = table_schema
88
98
  ORDER BY constraint_name, ordinal_position;
89
99
  SQL
90
100
  current_foreign_key = nil
91
101
  foreign_keys = []
92
102
 
103
+ namespace_prefix = table_namespace_prefix(table_name)
104
+
93
105
  results.each do |row|
94
- next unless table_name.casecmp(row[3]) == 0
106
+ next unless table_name_without_namespace(table_name).casecmp(row[3]) == 0
95
107
  if current_foreign_key != row[0]
96
- foreign_keys << ForeignKeyDefinition.new(row[0], row[1], [], row[3], [])
108
+ referenced_table_name = row[1]
109
+ referenced_table_name = namespace_prefix + referenced_table_name if table_namespace_prefix(referenced_table_name).blank?
110
+ references_table_name = row[3]
111
+ references_table_name = namespace_prefix + references_table_name if table_namespace_prefix(references_table_name).blank?
112
+ foreign_keys << ForeignKeyDefinition.new(row[0], referenced_table_name, [], references_table_name, [])
97
113
  current_foreign_key = row[0]
98
114
  end
99
115
 
@@ -134,6 +150,21 @@ module SchemaPlus
134
150
  when :now then 'CURRENT_TIMESTAMP'
135
151
  end
136
152
  end
153
+
154
+ private
155
+
156
+ def table_namespace_prefix(table_name)
157
+ table_name.to_s =~ /(.*[.])/ ? $1 : ""
158
+ end
159
+
160
+ def table_schema_sql(table_name)
161
+ table_name.to_s =~ /(.*)[.]/ ? "'#{$1}'" : "SCHEMA()"
162
+ end
163
+
164
+ def table_name_without_namespace(table_name)
165
+ table_name.to_s.sub /.*[.]/, ''
166
+ end
167
+
137
168
  end
138
169
  end
139
170
  end
@@ -53,6 +53,7 @@ module SchemaPlus
53
53
  alias_method_chain :rename_table, :schema_plus
54
54
  alias_method_chain :exec_cache, :schema_plus
55
55
  end
56
+ ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn.send(:include, PostgreSQLColumn) unless ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn.include?(PostgreSQLColumn)
56
57
  end
57
58
 
58
59
  # SchemaPlus provides the following extra options for Postgres
@@ -126,8 +127,8 @@ module SchemaPlus
126
127
  INNER JOIN pg_am m ON i.relam = m.oid
127
128
  WHERE i.relkind = 'i'
128
129
  AND d.indisprimary = 'f'
129
- AND t.relname = '#{table_name}'
130
- AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
130
+ AND t.relname = '#{table_name_without_namespace(table_name)}'
131
+ AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = #{namespace_sql(table_name)} )
131
132
  ORDER BY i.relname
132
133
  SQL
133
134
 
@@ -200,8 +201,8 @@ module SchemaPlus
200
201
  FROM pg_class t, pg_constraint f
201
202
  WHERE f.conrelid = t.oid
202
203
  AND f.contype = 'f'
203
- AND t.relname = '#{table_name}'
204
- AND t.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
204
+ AND t.relname = '#{table_name_without_namespace(table_name)}'
205
+ AND t.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = #{namespace_sql(table_name)} )
205
206
  SQL
206
207
  end
207
208
 
@@ -212,17 +213,19 @@ module SchemaPlus
212
213
  WHERE f.confrelid = t.oid
213
214
  AND f.conrelid = t2.oid
214
215
  AND f.contype = 'f'
215
- AND t.relname = '#{table_name}'
216
- AND t.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
216
+ AND t.relname = '#{table_name_without_namespace(table_name)}'
217
+ AND t.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = #{namespace_sql(table_name)} )
217
218
  SQL
218
219
  end
219
220
 
220
221
  def views(name = nil) #:nodoc:
221
- query(<<-SQL, name).map { |row| row[0] }
222
- SELECT viewname
223
- FROM pg_views
224
- WHERE schemaname = ANY (current_schemas(false))
222
+ sql = <<-SQL
223
+ SELECT viewname
224
+ FROM pg_views
225
+ WHERE schemaname = ANY (current_schemas(false))
225
226
  SQL
227
+ sql += " AND schemaname != 'postgis'" if adapter_name == 'PostGIS'
228
+ query(sql, name).map { |row| row[0] }
226
229
  end
227
230
 
228
231
  def view_definition(view_name, name = nil) #:nodoc:
@@ -238,11 +241,19 @@ module SchemaPlus
238
241
 
239
242
  private
240
243
 
244
+ def namespace_sql(table_name)
245
+ (table_name.to_s =~ /(.*)[.]/) ? "'#{$1}'" : "ANY (current_schemas(false))"
246
+ end
247
+
248
+ def table_name_without_namespace(table_name)
249
+ table_name.to_s.sub /.*[.]/, ''
250
+ end
251
+
241
252
  def load_foreign_keys(sql, name = nil) #:nodoc:
242
253
  foreign_keys = []
243
254
 
244
255
  query(sql, name).each do |row|
245
- if row[1] =~ /^FOREIGN KEY \((.+?)\) REFERENCES (.+?)\((.+?)\)( ON UPDATE (.+?))?( ON DELETE (.+?))?( (DEFERRABLE|NOT DEFERRABLE))?$/
256
+ if row[1] =~ /^FOREIGN KEY \((.+?)\) REFERENCES (.+?)\((.+?)\)( ON UPDATE (.+?))?( ON DELETE (.+?))?( (DEFERRABLE|NOT DEFERRABLE)( (INITIALLY DEFERRED|INITIALLY IMMEDIATE))?)?$/
246
257
  name = row[0]
247
258
  from_table_name = row[2]
248
259
  column_names = $1
@@ -251,6 +262,7 @@ module SchemaPlus
251
262
  on_update = $5
252
263
  on_delete = $7
253
264
  deferrable = $9 == "DEFERRABLE"
265
+ deferrable = :initially_deferred if ($11 == "INITIALLY DEFERRED" )
254
266
  on_update = on_update ? on_update.downcase.gsub(' ', '_').to_sym : :no_action
255
267
  on_delete = on_delete ? on_delete.downcase.gsub(' ', '_').to_sym : :no_action
256
268
 
@@ -22,6 +22,9 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
22
22
  config_options = {}
23
23
  options.keys.each { |key| config_options[key] = options.delete(key) if SchemaPlus.config.class.attributes.include? key }
24
24
 
25
+ # override rails' :force to cascade
26
+ drop_table(table, if_exists: true, cascade: true) if options.delete(:force)
27
+
25
28
  indexes = []
26
29
  create_table_without_schema_plus(table, options) do |table_definition|
27
30
  table_definition.schema_plus_config = SchemaPlus.config.merge(config_options)
@@ -21,6 +21,7 @@ module SchemaPlus
21
21
  alias_method_chain :indexes, :schema_plus
22
22
  alias_method_chain :rename_table, :schema_plus
23
23
  end
24
+ ::ActiveRecord::ConnectionAdapters::SQLiteColumn.send(:include, SQLiteColumn) unless ::ActiveRecord::ConnectionAdapters::SQLiteColumn.include?(SQLiteColumn)
24
25
  end
25
26
 
26
27
  def indexes_with_schema_plus(table_name, name = nil)
@@ -39,7 +40,6 @@ module SchemaPlus
39
40
  rename_indexes_and_foreign_keys(oldname, newname)
40
41
  end
41
42
 
42
-
43
43
  def add_foreign_key(table_name, column_names, references_table_name, references_column_names, options = {})
44
44
  raise NotImplementedError, "Sqlite3 does not support altering a table to add foreign key constraints (table #{table_name.inspect} column #{column_names.inspect})"
45
45
  end
@@ -48,6 +48,10 @@ module SchemaPlus
48
48
  raise NotImplementedError, "Sqlite3 does not support altering a table to remove foreign key constraints (table #{table_name.inspect} constraint #{foreign_key_name.inspect})"
49
49
  end
50
50
 
51
+ def drop_table(name, options={})
52
+ super(name, options.except(:cascade))
53
+ end
54
+
51
55
  def foreign_keys(table_name, name = nil)
52
56
  get_foreign_keys(table_name, name)
53
57
  end
@@ -83,22 +87,24 @@ module SchemaPlus
83
87
  \s*REFERENCES\s*[`"](.+?)[`"]\s*\((.+?)\)
84
88
  (\s+ON\s+UPDATE\s+(.+?))?
85
89
  (\s*ON\s+DELETE\s+(.+?))?
90
+ (\s*DEFERRABLE(\s+INITIALLY\s+DEFERRED)?)?
86
91
  \s*[,)]
87
92
  ]x
88
93
 
89
94
  foreign_keys = []
90
95
  results.each do |row|
91
96
  table_name = row["name"]
92
- row["sql"].scan(re).each do |d0, name, column_names, references_table_name, references_column_names, d1, on_update, d2, on_delete|
97
+ row["sql"].scan(re).each do |d0, name, column_names, references_table_name, references_column_names, d1, on_update, d2, on_delete, deferrable, initially_deferred|
93
98
  column_names = column_names.gsub('`', '').split(', ')
94
99
 
95
100
  references_column_names = references_column_names.gsub('`"', '').split(', ')
96
101
  on_update = on_update ? on_update.downcase.gsub(' ', '_').to_sym : :no_action
97
102
  on_delete = on_delete ? on_delete.downcase.gsub(' ', '_').to_sym : :no_action
103
+ deferrable = deferrable ? (initially_deferred ? :initially_deferred : true) : false
98
104
  foreign_keys << ForeignKeyDefinition.new(name,
99
105
  table_name, column_names,
100
106
  references_table_name, references_column_names,
101
- on_update, on_delete)
107
+ on_update, on_delete, deferrable)
102
108
  end
103
109
  end
104
110
 
@@ -1,3 +1,3 @@
1
1
  module SchemaPlus
2
- VERSION = "1.0.1"
2
+ VERSION = "1.1.0"
3
3
  end
data/runspecs CHANGED
@@ -97,7 +97,7 @@ combos.each_with_index do |combo, n|
97
97
  Tempfile.open('runspecs') do |file|
98
98
  system("(#{command}) 2>&1 | tee #{file.path}")
99
99
  file.rewind
100
- errs << "ruby #{ruby}, rails #{rails}#{db_adapter && ", db_adapter #{db_adapter}"}" if file.readlines.grep(/^Failed examples/).any?
100
+ errs << "ruby #{ruby}, rails #{rails}#{db_adapter && ", db_adapter #{db_adapter}"}" if file.readlines.grep(/(^Failed examples)|(rake aborted)/).any?
101
101
  end
102
102
  end
103
103
  puts errs.any? ? "\n*** #{errs.size} failures:\n\t#{errs.join("\n\t")}" : "\n*** #{combos.size > 1 ? 'all versions' : 'spec'} succeeded ***" unless o.dry_run
@@ -133,7 +133,7 @@ describe "Column definition" do
133
133
  subject { @sql}
134
134
 
135
135
  it "should give the default as false" do
136
- should match /boolean DEFAULT (\'f\'|0)/
136
+ should =~ /boolean DEFAULT (\'f\'|0)/
137
137
  end
138
138
  end
139
139
 
@@ -145,7 +145,7 @@ describe "Column definition" do
145
145
  subject { @sql}
146
146
 
147
147
  it "should give the default as true" do
148
- should match /boolean DEFAULT (\'t\'|1)/
148
+ should =~ /boolean DEFAULT (\'t\'|1)/
149
149
  end
150
150
  end
151
151
  end
data/spec/column_spec.rb CHANGED
@@ -8,6 +8,16 @@ describe "Column" do
8
8
 
9
9
  let(:migration) { ::ActiveRecord::Migration }
10
10
 
11
+ context "JSON serialization" do
12
+ before(:each) do
13
+ create_table(User, :login => { :index => true})
14
+ @login = User.columns.find{|column| column.name == "login"}
15
+ end
16
+ it "works properly" do
17
+ JSON.parse(@login.to_json).should include("name" => "login", "type" => "string")
18
+ end
19
+ end
20
+
11
21
  context "regarding indexes" do
12
22
 
13
23
  context "if not unique" do
@@ -78,7 +88,7 @@ describe "Column" do
78
88
  User.columns.find{|column| column.name == "login"}.required_on.should == :save
79
89
  end
80
90
 
81
- it "must have a value on :updae if there's default" do
91
+ it "must have a value on :update if there's default" do
82
92
  create_table(User, :login => { :null => false, :default => "foo" })
83
93
  User.columns.find{|column| column.name == "login"}.required_on.should == :update
84
94
  end
@@ -4,10 +4,20 @@ describe "Foreign Key definition" do
4
4
 
5
5
  let(:definition) { SchemaPlus::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new("posts_user_fkey", :posts, :user, :users, :id) }
6
6
 
7
- it "it is dumped to sql with quoted values" do
7
+ it "dumps to sql with quoted values" do
8
8
  definition.to_sql.should == %Q{CONSTRAINT posts_user_fkey FOREIGN KEY (#{quote_column_name('user')}) REFERENCES #{quote_table_name('users')} (#{quote_column_name('id')})}
9
9
  end
10
10
 
11
+ it "dumps to sql with deferrable values" do
12
+ deferred_definition = SchemaPlus::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new("posts_user_fkey", :posts, :user, :users, :id, nil, nil, true)
13
+ deferred_definition.to_sql.should == %Q{CONSTRAINT posts_user_fkey FOREIGN KEY (#{quote_column_name('user')}) REFERENCES #{quote_table_name('users')} (#{quote_column_name('id')}) DEFERRABLE}
14
+ end
15
+
16
+ it "dumps to sql with initially deferrable values" do
17
+ initially_deferred_definition = SchemaPlus::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new("posts_user_fkey", :posts, :user, :users, :id, nil, nil, :initially_deferred)
18
+ initially_deferred_definition.to_sql.should == %Q{CONSTRAINT posts_user_fkey FOREIGN KEY (#{quote_column_name('user')}) REFERENCES #{quote_table_name('users')} (#{quote_column_name('id')}) DEFERRABLE INITIALLY DEFERRED}
19
+ end
20
+
11
21
  def quote_table_name(table)
12
22
  ActiveRecord::Base.connection.quote_table_name(table)
13
23
  end
@@ -4,7 +4,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
4
4
  describe ActiveRecord::Migration do
5
5
  include SchemaPlusHelpers
6
6
 
7
- before(:all) do
7
+ before(:each) do
8
8
  define_schema(:auto_create => true) do
9
9
 
10
10
  create_table :users, :force => true do |t|
@@ -293,14 +293,14 @@ describe ActiveRecord::Migration do
293
293
  end
294
294
  end
295
295
 
296
- it "should use default on_update action" do
297
- with_fk_config(:on_update => :cascade) do
296
+ [false, true, :initially_deferred].each do |status|
297
+ it "should create and detect deferrable #{status.inspect}" do
298
298
  recreate_table @model do |t|
299
- t.integer :user_id
299
+ t.integer :user_id, :on_delete => :cascade, :deferrable => status
300
300
  end
301
- @model.should reference.on(:user_id).on_update(:cascade)
301
+ @model.should reference.on(:user_id).deferrable(status)
302
302
  end
303
- end
303
+ end unless SchemaPlusHelpers.mysql?
304
304
 
305
305
  it "should use default on_delete action" do
306
306
  with_fk_config(:on_delete => :cascade) do
@@ -121,6 +121,98 @@ describe "with multiple schemas" do
121
121
 
122
122
  end
123
123
 
124
+ context "foreign key migrations" do
125
+ before(:each) do
126
+ define_schema do
127
+ create_table "items", :force => true do |t|
128
+ end
129
+ create_table "schema_plus_test2.groups", :force => true do |t|
130
+ end
131
+ create_table "schema_plus_test2.members", :force => true do |t|
132
+ t.integer :item_id, :foreign_key => true unless SchemaPlusHelpers.mysql?
133
+ t.integer :group_id, :foreign_key => { references: "schema_plus_test2.groups" }
134
+ end
135
+ end
136
+ class Group < ::ActiveRecord::Base
137
+ self.table_name = "schema_plus_test2.groups"
138
+ end
139
+ class Item < ::ActiveRecord::Base
140
+ self.table_name = "items"
141
+ end
142
+ class Member < ::ActiveRecord::Base
143
+ self.table_name = "schema_plus_test2.members"
144
+ end
145
+ end
146
+
147
+ around(:each) do |example|
148
+ begin
149
+ example.run
150
+ ensure
151
+ connection.execute 'DROP TABLE IF EXISTS schema_plus_test2.members'
152
+ connection.execute 'DROP TABLE IF EXISTS schema_plus_test2.groups'
153
+ connection.execute 'DROP TABLE IF EXISTS items'
154
+ end
155
+ end
156
+
157
+ it "should find foreign keys" do
158
+ Member.foreign_keys.should_not be_empty
159
+ end
160
+
161
+ it "should find reverse foreign keys" do
162
+ Group.reverse_foreign_keys.should_not be_empty
163
+ end
164
+
165
+ it "should reference table in same schema" do
166
+ Member.foreign_keys.map(&:references_table_name).should include "schema_plus_test2.groups"
167
+ end
168
+
169
+ it "should reference table in default schema" do
170
+ Member.foreign_keys.map(&:references_table_name).should include "items"
171
+ end unless SchemaPlusHelpers.mysql?
172
+
173
+ it "should include the schema in the constraint name" do
174
+ expected_names = ["fk_schema_plus_test2_members_group_id"]
175
+ expected_names << "fk_schema_plus_test2_members_item_id" unless SchemaPlusHelpers.mysql?
176
+ Member.foreign_keys.map(&:name).should =~ expected_names
177
+ end
178
+ end
179
+
180
+ if SchemaPlusHelpers.postgresql?
181
+ context "when using PostGIS" do
182
+ before(:all) do
183
+ begin
184
+ connection.execute "CREATE SCHEMA postgis"
185
+ rescue ActiveRecord::StatementInvalid => e
186
+ raise unless e.message =~ /already exists/
187
+ end
188
+ end
189
+
190
+ around (:each) do |example|
191
+ begin
192
+ connection.execute "SET search_path to '$user','public','postgis'"
193
+ example.run
194
+ ensure
195
+ connection.execute "SET search_path to '$user','public'"
196
+ end
197
+ end
198
+
199
+ before(:each) do
200
+ connection.stub :adapter_name => 'PostGIS'
201
+ end
202
+
203
+ it "should hide views in postgis schema" do
204
+ begin
205
+ connection.create_view "postgis.hidden", "select 1", :force => true
206
+ connection.create_view :myview, "select 2", :force => true
207
+ connection.views.should == ["myview"]
208
+ ensure
209
+ connection.execute 'DROP VIEW postgis.hidden' rescue nil
210
+ connection.execute 'DROP VIEW myview' rescue nil
211
+ end
212
+ end
213
+ end
214
+ end
215
+
124
216
  end
125
217
 
126
218