activerecord-postgresql-extensions 0.0.12 → 0.1.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 (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