activerecord-postgresql-extensions 0.0.12 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +3 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -2
  5. data/Rakefile +4 -17
  6. data/activerecord-postgresql-extensions.gemspec +13 -57
  7. data/lib/{postgresql_extensions/postgresql_adapter_extensions.rb → active_record/postgresql_extensions/adapter_extensions.rb} +44 -46
  8. data/lib/{postgresql_extensions/postgresql_constraints.rb → active_record/postgresql_extensions/constraints.rb} +121 -10
  9. data/lib/{postgresql_extensions/postgresql_extensions.rb → active_record/postgresql_extensions/extensions.rb} +1 -1
  10. data/lib/{postgresql_extensions → active_record/postgresql_extensions}/foreign_key_associations.rb +9 -1
  11. data/lib/{postgresql_extensions/postgresql_functions.rb → active_record/postgresql_extensions/functions.rb} +9 -3
  12. data/lib/{postgresql_extensions/postgresql_geometry.rb → active_record/postgresql_extensions/geometry.rb} +111 -35
  13. data/lib/{postgresql_extensions/postgresql_indexes.rb → active_record/postgresql_extensions/indexes.rb} +4 -2
  14. data/lib/{postgresql_extensions/postgresql_languages.rb → active_record/postgresql_extensions/languages.rb} +1 -1
  15. data/lib/{postgresql_extensions/postgresql_permissions.rb → active_record/postgresql_extensions/permissions.rb} +3 -3
  16. data/lib/active_record/postgresql_extensions/postgis.rb +53 -0
  17. data/lib/{postgresql_extensions/postgresql_roles.rb → active_record/postgresql_extensions/roles.rb} +1 -1
  18. data/lib/{postgresql_extensions/postgresql_rules.rb → active_record/postgresql_extensions/rules.rb} +3 -3
  19. data/lib/{postgresql_extensions/postgresql_schemas.rb → active_record/postgresql_extensions/schemas.rb} +1 -1
  20. data/lib/{postgresql_extensions/postgresql_sequences.rb → active_record/postgresql_extensions/sequences.rb} +2 -2
  21. data/lib/{postgresql_extensions/postgresql_tables.rb → active_record/postgresql_extensions/tables.rb} +18 -4
  22. data/lib/{postgresql_extensions/postgresql_tablespaces.rb → active_record/postgresql_extensions/tablespaces.rb} +1 -1
  23. data/lib/{postgresql_extensions/postgresql_text_search.rb → active_record/postgresql_extensions/text_search.rb} +3 -3
  24. data/lib/{postgresql_extensions/postgresql_triggers.rb → active_record/postgresql_extensions/triggers.rb} +1 -1
  25. data/lib/{postgresql_extensions/postgresql_types.rb → active_record/postgresql_extensions/types.rb} +1 -1
  26. data/lib/active_record/postgresql_extensions/utils.rb +23 -0
  27. data/lib/active_record/postgresql_extensions/version.rb +7 -0
  28. data/lib/{postgresql_extensions/postgresql_views.rb → active_record/postgresql_extensions/views.rb} +2 -2
  29. data/lib/activerecord-postgresql-extensions.rb +23 -22
  30. data/test/adapter_tests.rb +9 -9
  31. data/test/constraints_tests.rb +155 -0
  32. data/test/database.yml +17 -0
  33. data/test/geometry_tests.rb +224 -52
  34. data/test/index_tests.rb +16 -1
  35. data/test/rules_tests.rb +4 -4
  36. data/test/sequences_tests.rb +0 -22
  37. data/test/tables_tests.rb +28 -31
  38. data/test/test_helper.rb +70 -23
  39. data/test/trigger_tests.rb +5 -5
  40. metadata +112 -25
  41. data/VERSION +0 -1
@@ -15,7 +15,7 @@ module ActiveRecord
15
15
  end
16
16
 
17
17
  module ConnectionAdapters
18
- class PostgreSQLAdapter < AbstractAdapter
18
+ class PostgreSQLAdapter
19
19
  # Creates a PostgreSQL rule.
20
20
  #
21
21
  # +event+ can be one of <tt>:select</tt>, <tt>:insert</tt>,
@@ -33,7 +33,7 @@ module ActiveRecord
33
33
  # * <tt>:force</tt> - add an <tt>OR REPLACE</tt> clause to the
34
34
  # command.
35
35
  # * <tt>:conditions</tt> - a <tt>WHERE</tt> clause to limit the
36
- # rule.
36
+ # rule. Alternatively, you can also use the <tt>:where</tt> option.
37
37
  #
38
38
  # ==== Examples
39
39
  #
@@ -79,7 +79,7 @@ module ActiveRecord
79
79
  sql = 'CREATE '
80
80
  sql << ' OR REPLACE ' if options[:force]
81
81
  sql << "RULE #{base.quote_rule(name)} AS ON #{event.to_s.upcase} TO #{base.quote_table_name(table)} "
82
- sql << "WHERE #{options[:conditions]} " if options[:conditions]
82
+ sql << "WHERE #{options[:conditions] || options[:where]} " if options[:conditions] || options[:where]
83
83
  sql << "DO #{action.to_s.upcase} "
84
84
  sql << if commands.to_s.upcase == 'NOTHING'
85
85
  'NOTHING'
@@ -3,7 +3,7 @@ require 'active_record/connection_adapters/postgresql_adapter'
3
3
 
4
4
  module ActiveRecord
5
5
  module ConnectionAdapters
6
- class PostgreSQLAdapter < AbstractAdapter
6
+ class PostgreSQLAdapter
7
7
  # Creates a new PostgreSQL schema.
8
8
  #
9
9
  # Note that you can grant privileges on schemas using the
@@ -12,7 +12,7 @@ module ActiveRecord
12
12
  end
13
13
 
14
14
  module ConnectionAdapters
15
- class PostgreSQLAdapter < AbstractAdapter
15
+ class PostgreSQLAdapter
16
16
  # Creates a sequence.
17
17
  #
18
18
  # Note that you can grant privileges on sequences using the
@@ -73,7 +73,7 @@ module ActiveRecord
73
73
 
74
74
  # Renames the sequence.
75
75
  def rename_sequence(name, rename, options = {})
76
- execute("ALTER SEQUENCE #{quote_sequence(name)} RENAME TO #{quote_generic_ignore_schema(rename)};")
76
+ execute("ALTER SEQUENCE #{quote_sequence(name)} RENAME TO #{quote_generic_ignore_scoped_schema(rename)};")
77
77
  end
78
78
 
79
79
  # Alters the sequence's schema.
@@ -1,4 +1,6 @@
1
1
 
2
+ require 'active_record/connection_adapters/postgresql_adapter'
3
+
2
4
  module ActiveRecord
3
5
  class InvalidLikeTypes < ActiveRecordError #:nodoc:
4
6
  def initialize(likes)
@@ -10,7 +12,7 @@ module ActiveRecord
10
12
  end
11
13
 
12
14
  module ConnectionAdapters
13
- class PostgreSQLAdapter < AbstractAdapter
15
+ class PostgreSQLAdapter
14
16
  # Set the schema of a table.
15
17
  def alter_table_schema(table_name, schema, options = {})
16
18
  execute "ALTER TABLE #{quote_schema(table_name)} SET SCHEMA #{quote_schema(schema)};"
@@ -142,7 +144,7 @@ module ActiveRecord
142
144
  # capabilities. You can still access the original method via
143
145
  # original_rename_table.
144
146
  def rename_table(name, new_name, options = {})
145
- execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_generic_ignore_schema(new_name)};"
147
+ execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_generic_ignore_scoped_schema(new_name)};"
146
148
  end
147
149
 
148
150
  private
@@ -193,7 +195,7 @@ module ActiveRecord
193
195
  sql << "(\n "
194
196
 
195
197
  ary = @columns.collect(&:to_sql)
196
- ary << @like if @like
198
+ ary << @like if defined?(@like) && @like
197
199
  ary << @table_constraints unless @table_constraints.empty?
198
200
  sql << ary * ",\n "
199
201
  sql << "\n)"
@@ -257,6 +259,12 @@ module ActiveRecord
257
259
  @table_constraints << PostgreSQLForeignKeyConstraint.new(@base, columns, ref_table, *args)
258
260
  end
259
261
 
262
+ # Add an EXCLUDE constraint to the table. See PostgreSQLExcludeConstraint
263
+ # for more details.
264
+ def exclude(excludes, options = {})
265
+ @table_constraints << PostgreSQLExcludeConstraint.new(@base, table_name, excludes, options)
266
+ end
267
+
260
268
  def column_with_constraints(name, type, *args) #:nodoc:
261
269
  options = args.extract_options!
262
270
  check = options.delete(:check)
@@ -265,7 +273,13 @@ module ActiveRecord
265
273
  column_without_constraints(name, type, options)
266
274
 
267
275
  if check
268
- @table_constraints << Array(check).collect do |c|
276
+ check = if !check.is_a?(Array)
277
+ [ check ]
278
+ else
279
+ check
280
+ end
281
+
282
+ @table_constraints << check.collect do |c|
269
283
  if c.is_a?(Hash)
270
284
  PostgreSQLCheckConstraint.new(@base, c.delete(:expression), c)
271
285
  else
@@ -9,7 +9,7 @@ module ActiveRecord
9
9
  end
10
10
 
11
11
  module ConnectionAdapters
12
- class PostgreSQLAdapter < AbstractAdapter
12
+ class PostgreSQLAdapter
13
13
  # Creates a new PostgreSQL tablespace.
14
14
  def create_tablespace(name, location, options = {})
15
15
  sql = "CREATE TABLESPACE #{quote_tablespace(name)} "
@@ -3,7 +3,7 @@ require 'active_record/connection_adapters/postgresql_adapter'
3
3
 
4
4
  module ActiveRecord
5
5
  module ConnectionAdapters
6
- class PostgreSQLAdapter < AbstractAdapter
6
+ class PostgreSQLAdapter
7
7
  # Creates a new PostgreSQL text search configuration. You must provide
8
8
  # either a :parser_name or a :source_config option as per the PostgreSQL
9
9
  # text search docs.
@@ -16,7 +16,7 @@ module ActiveRecord
16
16
 
17
17
  sql = "CREATE TEXT SEARCH CONFIGURATION #{quote_generic_with_schema(name)} ("
18
18
 
19
- ignore_schema do
19
+ ignore_scoped_schema do
20
20
  sql << if options[:parser_name]
21
21
  "PARSER = #{quote_generic_with_schema(options[:parser_name])}"
22
22
  else
@@ -110,7 +110,7 @@ module ActiveRecord
110
110
  execute("#{sql};")
111
111
  end
112
112
 
113
- def rename_text_search_configuration(old_name, new_name)
113
+ def rename_text_search_configuration(old_name, new_name)
114
114
  execute("ALTER TEXT SEARCH CONFIGURATION %s RENAME TO %s;" % [
115
115
  quote_generic_with_schema(old_name),
116
116
  quote_generic_with_schema(new_name)
@@ -39,7 +39,7 @@ module ActiveRecord
39
39
  end
40
40
 
41
41
  module ConnectionAdapters
42
- class PostgreSQLAdapter < AbstractAdapter
42
+ class PostgreSQLAdapter
43
43
  # Creates a PostgreSQL trigger.
44
44
  #
45
45
  # The +called+ argument specifies when the trigger is called and
@@ -3,7 +3,7 @@ require 'active_record/connection_adapters/postgresql_adapter'
3
3
 
4
4
  module ActiveRecord
5
5
  module ConnectionAdapters
6
- class PostgreSQLAdapter < AbstractAdapter
6
+ class PostgreSQLAdapter
7
7
  # Returns an Array of available languages.
8
8
  def types(name = nil)
9
9
  query(%{SELECT typname FROM pg_type;}, name).map { |row| row[0] }
@@ -0,0 +1,23 @@
1
+
2
+ module ActiveRecord
3
+ module PostgreSQLExtensions
4
+ module Utils
5
+ class << self
6
+ def hash_or_array_of_hashes(arg)
7
+ case arg
8
+ when Hash
9
+ [ arg ]
10
+ when Array
11
+ if arg.detect { |e| !e.is_a?(Hash) }
12
+ raise ArgumentError.new("Expected an Array of Hashes")
13
+ else
14
+ arg
15
+ end
16
+ else
17
+ raise ArgumentError.new("Expected either a Hash or an Array of Hashes")
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+
2
+ module ActiveRecord
3
+ module PostgreSQLExtensions
4
+ VERSION = "0.1.0"
5
+ end
6
+ end
7
+
@@ -3,7 +3,7 @@ require 'active_record/connection_adapters/postgresql_adapter'
3
3
 
4
4
  module ActiveRecord
5
5
  module ConnectionAdapters
6
- class PostgreSQLAdapter < AbstractAdapter
6
+ class PostgreSQLAdapter
7
7
  # Creates a new PostgreSQL view.
8
8
  #
9
9
  # +name+ is the name of the view. View quoting works the same as
@@ -59,7 +59,7 @@ module ActiveRecord
59
59
 
60
60
  # Renames a view.
61
61
  def rename_view(name, new_name, options = {})
62
- execute "ALTER TABLE #{quote_view_name(name)} RENAME TO #{quote_generic_ignore_schema(new_name)};"
62
+ execute "ALTER TABLE #{quote_view_name(name)} RENAME TO #{quote_generic_ignore_scoped_schema(new_name)};"
63
63
  end
64
64
 
65
65
  # Change the ownership of a view.
@@ -1,34 +1,35 @@
1
1
 
2
2
  require 'active_record/connection_adapters/postgresql_adapter'
3
3
 
4
- module PostgreSQLExtensions
4
+ module ActiveRecord
5
+ module PostgreSQLExtensions
6
+ end
5
7
  end
6
8
 
7
- dirname = File.join(File.dirname(__FILE__), 'postgresql_extensions')
9
+ dirname = File.join(File.dirname(__FILE__), *%w{ active_record postgresql_extensions })
8
10
 
9
11
  %w{
10
- postgresql_adapter_extensions
11
- postgresql_constraints
12
- postgresql_tables
13
- postgresql_tablespaces
14
- postgresql_indexes
15
- postgresql_permissions
16
- postgresql_schemas
17
- postgresql_languages
18
- postgresql_rules
19
- postgresql_functions
20
- postgresql_sequences
21
- postgresql_triggers
22
- postgresql_views
23
- postgresql_geometry
24
- postgresql_types
25
- postgresql_roles
26
- postgresql_text_search
27
- postgresql_extensions
12
+ adapter_extensions
13
+ constraints
14
+ tables
15
+ tablespaces
16
+ indexes
17
+ permissions
18
+ schemas
19
+ languages
20
+ rules
21
+ functions
22
+ sequences
23
+ triggers
24
+ views
25
+ geometry
26
+ types
27
+ roles
28
+ text_search
29
+ extensions
28
30
  foreign_key_associations
29
31
  }.each do |file|
30
32
  require File.join(dirname, file)
31
33
  end
32
34
 
33
- ActiveRecord::Base.send(:include, PostgreSQLExtensions::ActiveRecord::ForeignKeyAssociations)
34
-
35
+ ActiveRecord::Base.send(:include, ActiveRecord::PostgreSQLExtensions::ForeignKeyAssociations)
@@ -13,15 +13,15 @@ class AdapterExtensionTests < Test::Unit::TestCase
13
13
  assert_equal(%{"foo"."bar"}, ARBC.quote_table_name(:foo => :bar))
14
14
  end
15
15
 
16
- def test_quote_table_name_with_current_schema
16
+ def test_quote_table_name_with_current_scoped_schema
17
17
  assert_equal(%{"foo"."bar"}, ARBC.with_schema(:foo) {
18
18
  ARBC.quote_table_name(:bar)
19
19
  })
20
20
  end
21
21
 
22
- def test_quote_table_name_with_current_schema_ignored
22
+ def test_quote_table_name_with_current_scoped_schema_ignored
23
23
  assert_equal(%{"bar"}, ARBC.with_schema(:foo) {
24
- ARBC.ignore_schema {
24
+ ARBC.ignore_scoped_schema {
25
25
  ARBC.quote_table_name(:bar)
26
26
  }
27
27
  })
@@ -60,7 +60,7 @@ class AdapterExtensionTests < Test::Unit::TestCase
60
60
  %{SET ROLE "foo";},
61
61
  %{SET LOCAL ROLE "foo";},
62
62
  %{SET SESSION ROLE "foo";}
63
- ], ARBC.statements)
63
+ ], statements)
64
64
 
65
65
  assert_raise(ArgumentError) do
66
66
  ARBC.set_role('foo', :duration => :nonsense)
@@ -69,7 +69,7 @@ class AdapterExtensionTests < Test::Unit::TestCase
69
69
 
70
70
  def test_reset_role
71
71
  ARBC.reset_role
72
- assert_equal([ 'RESET ROLE;' ], ARBC.statements)
72
+ assert_equal([ 'RESET ROLE;' ], statements)
73
73
  end
74
74
 
75
75
  def test_current_role
@@ -79,7 +79,7 @@ class AdapterExtensionTests < Test::Unit::TestCase
79
79
  assert_equal([
80
80
  'SELECT current_role;',
81
81
  'SELECT current_role;'
82
- ], ARBC.statements)
82
+ ], statements)
83
83
  end
84
84
 
85
85
  def test_enable_triggers
@@ -92,7 +92,7 @@ class AdapterExtensionTests < Test::Unit::TestCase
92
92
  %{ALTER TABLE "foo" ENABLE TRIGGER "bar";},
93
93
  %{ALTER TABLE "foo" ENABLE TRIGGER "bar";},
94
94
  %{ALTER TABLE "foo" ENABLE TRIGGER "baz";}
95
- ], ARBC.statements)
95
+ ], statements)
96
96
  end
97
97
 
98
98
  def test_disable_triggers
@@ -105,7 +105,7 @@ class AdapterExtensionTests < Test::Unit::TestCase
105
105
  %{ALTER TABLE "foo" DISABLE TRIGGER "bar";},
106
106
  %{ALTER TABLE "foo" DISABLE TRIGGER "bar";},
107
107
  %{ALTER TABLE "foo" DISABLE TRIGGER "baz";}
108
- ], ARBC.statements)
108
+ ], statements)
109
109
  end
110
110
 
111
111
  def test_without_triggers
@@ -139,6 +139,6 @@ class AdapterExtensionTests < Test::Unit::TestCase
139
139
  %{ALTER TABLE "foo" DISABLE TRIGGER "baz";},
140
140
  %{ALTER TABLE "foo" ENABLE TRIGGER "bar";},
141
141
  %{ALTER TABLE "foo" ENABLE TRIGGER "baz";}
142
- ], ARBC.statements)
142
+ ], statements)
143
143
  end
144
144
  end
@@ -60,6 +60,52 @@ EOF
60
60
  ], statements)
61
61
  end
62
62
 
63
+ def test_foreign_key_in_column_definition
64
+ Mig.create_table('foo') do |t|
65
+ t.integer :foo_id, :references => {
66
+ :table => :foo,
67
+ :on_delete => :set_null,
68
+ :on_update => :cascade
69
+ }
70
+
71
+ t.integer :bar_id, :references => :bar
72
+
73
+ t.integer :baz_id, :references => [ :baz ]
74
+ end
75
+
76
+ assert_equal([
77
+ %{CREATE TABLE "foo" (
78
+ "id" serial primary key,
79
+ "foo_id" integer,
80
+ "bar_id" integer,
81
+ "baz_id" integer,
82
+ FOREIGN KEY ("foo_id") REFERENCES "foo" ON DELETE SET NULL ON UPDATE CASCADE,
83
+ FOREIGN KEY ("bar_id") REFERENCES "bar",
84
+ FOREIGN KEY ("baz_id") REFERENCES "baz"
85
+ );} ], statements)
86
+ end
87
+
88
+ def test_foreign_key_in_table_definition
89
+ Mig.create_table('foo') do |t|
90
+ t.integer :schabba_id
91
+ t.integer :doo_id
92
+
93
+ t.foreign_key :schabba_id, :bar
94
+ t.foreign_key :doo_id, :baz
95
+ t.foreign_key [ :schabba_id, :doo_id ], :bar, [ :schabba_id, :doo_id ]
96
+ end
97
+
98
+ assert_equal([
99
+ %{CREATE TABLE "foo" (
100
+ "id" serial primary key,
101
+ "schabba_id" integer,
102
+ "doo_id" integer,
103
+ FOREIGN KEY ("schabba_id") REFERENCES "bar",
104
+ FOREIGN KEY ("doo_id") REFERENCES "baz",
105
+ FOREIGN KEY ("schabba_id", "doo_id") REFERENCES "bar" ("schabba_id", "doo_id")
106
+ );} ], statements)
107
+ end
108
+
63
109
  def test_add_foreign_key
64
110
  Mig.add_foreign_key(:foo, :bar_id, :bar)
65
111
  Mig.add_foreign_key(:foo, :bar_id, :bar, :ogc_fid, :name => 'bar_fk')
@@ -86,6 +132,56 @@ EOF
86
132
  ], statements)
87
133
  end
88
134
 
135
+ def test_check_constraint_in_column_definition
136
+ Mig.create_table('foo') do |t|
137
+ t.integer :foo_id, :check => "foo_id != 1"
138
+ t.integer :bar_id, :check => { :expression => "bar_id != 1", :name => "bar_id_not_1" }
139
+ t.integer :baz_id, :check => [ "baz_id != 1", {
140
+ :expression => "baz_id > 10",
141
+ :name => "baz_id_gt_10"
142
+ } ]
143
+ end
144
+
145
+ assert_equal([
146
+ %{CREATE TABLE "foo" (
147
+ "id" serial primary key,
148
+ "foo_id" integer,
149
+ "bar_id" integer,
150
+ "baz_id" integer,
151
+ CHECK (foo_id != 1),
152
+ CONSTRAINT "bar_id_not_1" CHECK (bar_id != 1),
153
+ CHECK (baz_id != 1),
154
+ CONSTRAINT "baz_id_gt_10" CHECK (baz_id > 10)
155
+ );} ], statements)
156
+ end
157
+
158
+ def test_check_constraint_in_table_definition
159
+ Mig.create_table('foo') do |t|
160
+ t.integer :foo_id
161
+ t.integer :bar_id
162
+ t.integer :baz_id
163
+
164
+ t.check_constraint "foo_id != 1"
165
+ t.check_constraint "bar_id != 1", :name => "bar_id_not_1"
166
+ t.check_constraint "baz_id != 1"
167
+ t.check_constraint "baz_id > 10", {
168
+ :name => "baz_id_gt_10"
169
+ }
170
+ end
171
+
172
+ assert_equal([
173
+ %{CREATE TABLE "foo" (
174
+ "id" serial primary key,
175
+ "foo_id" integer,
176
+ "bar_id" integer,
177
+ "baz_id" integer,
178
+ CHECK (foo_id != 1),
179
+ CONSTRAINT "bar_id_not_1" CHECK (bar_id != 1),
180
+ CHECK (baz_id != 1),
181
+ CONSTRAINT "baz_id_gt_10" CHECK (baz_id > 10)
182
+ );} ], statements)
183
+ end
184
+
89
185
  def test_add_check_constraint
90
186
  Mig.add_check_constraint(:foo, 'length(name) < 100')
91
187
  Mig.add_check_constraint(:foo, 'length(name) < 100', :name => 'name_length_check')
@@ -95,4 +191,63 @@ EOF
95
191
  "ALTER TABLE \"foo\" ADD CONSTRAINT \"name_length_check\" CHECK (length(name) < 100);"
96
192
  ], statements)
97
193
  end
194
+
195
+ def test_add_exclude_constraint
196
+ Mig.add_exclude_constraint(:foo, :element => 'length(name)', :with => '=')
197
+
198
+ Mig.add_exclude_constraint(:foo, {
199
+ :element => 'length(name)',
200
+ :with => '='
201
+ }, {
202
+ :name => 'exclude_name_length'
203
+ })
204
+
205
+ Mig.add_exclude_constraint(:foo, {
206
+ :element => 'length(name)',
207
+ :with => '='
208
+ }, {
209
+ :name => 'exclude_name_length',
210
+ :using => :gist
211
+ })
212
+
213
+ Mig.add_exclude_constraint(:foo, [{
214
+ :element => 'length(name)',
215
+ :with => '='
216
+ }, {
217
+ :element => 'length(title)',
218
+ :with => '='
219
+ }])
220
+
221
+ Mig.add_exclude_constraint(:foo, {
222
+ :element => 'length(name)',
223
+ :with => '='
224
+ }, {
225
+ :conditions => Foo.send(:sanitize_sql, {
226
+ :id => [1,2,3,4]
227
+ })
228
+ })
229
+
230
+ Mig.add_exclude_constraint(:foo, {
231
+ :element => 'length(name)',
232
+ :with => '='
233
+ }, {
234
+ :tablespace => 'fubar',
235
+ :index_parameters => 'FILLFACTOR=10'
236
+ })
237
+
238
+ escaped_array = if ActiveRecord::VERSION::STRING >= "3.0"
239
+ "(1, 2, 3, 4)"
240
+ else
241
+ "(1,2,3,4)"
242
+ end
243
+
244
+ assert_equal([
245
+ %{ALTER TABLE "foo" ADD EXCLUDE (length(name) WITH =);},
246
+ %{ALTER TABLE "foo" ADD CONSTRAINT "exclude_name_length" EXCLUDE (length(name) WITH =);},
247
+ %{ALTER TABLE "foo" ADD CONSTRAINT "exclude_name_length" EXCLUDE USING "gist" (length(name) WITH =);},
248
+ %{ALTER TABLE "foo" ADD EXCLUDE (length(name) WITH =, length(title) WITH =);},
249
+ %{ALTER TABLE "foo" ADD EXCLUDE (length(name) WITH =) WHERE ("foos"."id" IN #{escaped_array});},
250
+ %{ALTER TABLE "foo" ADD EXCLUDE (length(name) WITH =) WITH (FILLFACTOR=10) USING INDEX TABLESPACE "fubar";}
251
+ ], statements)
252
+ end
98
253
  end