activerecord-postgresql-extensions 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +23 -0
- data/README.rdoc +32 -0
- data/Rakefile +42 -0
- data/VERSION +1 -0
- data/lib/activerecord-postgresql-extensions.rb +30 -0
- data/lib/postgresql_extensions/foreign_key_associations.rb +367 -0
- data/lib/postgresql_extensions/postgresql_adapter_extensions.rb +646 -0
- data/lib/postgresql_extensions/postgresql_constraints.rb +579 -0
- data/lib/postgresql_extensions/postgresql_functions.rb +345 -0
- data/lib/postgresql_extensions/postgresql_geometry.rb +212 -0
- data/lib/postgresql_extensions/postgresql_indexes.rb +219 -0
- data/lib/postgresql_extensions/postgresql_languages.rb +80 -0
- data/lib/postgresql_extensions/postgresql_permissions.rb +322 -0
- data/lib/postgresql_extensions/postgresql_rules.rb +112 -0
- data/lib/postgresql_extensions/postgresql_schemas.rb +49 -0
- data/lib/postgresql_extensions/postgresql_sequences.rb +222 -0
- data/lib/postgresql_extensions/postgresql_tables.rb +308 -0
- data/lib/postgresql_extensions/postgresql_triggers.rb +131 -0
- data/lib/postgresql_extensions/postgresql_types.rb +17 -0
- data/lib/postgresql_extensions/postgresql_views.rb +103 -0
- data/postgresql-extensions.gemspec +50 -0
- data/test/adapter_test.rb +45 -0
- data/test/constraints_test.rb +98 -0
- data/test/functions_test.rb +112 -0
- data/test/geometry_test.rb +43 -0
- data/test/index_test.rb +68 -0
- data/test/languages_test.rb +48 -0
- data/test/permissions_test.rb +163 -0
- data/test/rules_test.rb +32 -0
- data/test/schemas_test.rb +43 -0
- data/test/sequences_test.rb +90 -0
- data/test/tables_test.rb +49 -0
- data/test/test_helper.rb +64 -0
- metadata +97 -0
@@ -0,0 +1,131 @@
|
|
1
|
+
|
2
|
+
require 'active_record/connection_adapters/postgresql_adapter'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
class InvalidTriggerCallType < ActiveRecordError #:nodoc:
|
6
|
+
def initialize(called)
|
7
|
+
super("Invalid trigger call type - #{called}")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class InvalidTriggerEvents < ActiveRecordError #:nodoc:
|
12
|
+
def initialize(events)
|
13
|
+
super("Invalid trigger event(s) - #{events.inspect}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module ConnectionAdapters
|
18
|
+
class PostgreSQLAdapter < AbstractAdapter
|
19
|
+
# Creates a PostgreSQL trigger.
|
20
|
+
#
|
21
|
+
# The +called+ argument specifies when the trigger is called and
|
22
|
+
# can be either <tt>:before</tt> or <tt>:after</tt>.
|
23
|
+
#
|
24
|
+
# +events+ can be on or more of <tt>:insert</tt>,
|
25
|
+
# <tt>:update</tt> or <tt>:delete</tt>. There are no
|
26
|
+
# <tt>:select</tt> triggers, as SELECT generally doesn't modify
|
27
|
+
# the database.
|
28
|
+
#
|
29
|
+
# +table+ is obviously the table the trigger will be created on
|
30
|
+
# while +function+ is the name of the procedure to call when the
|
31
|
+
# trigger is fired.
|
32
|
+
#
|
33
|
+
# ==== Options
|
34
|
+
#
|
35
|
+
# * <tt>:for_each</tt> - defines whether the trigger will be fired
|
36
|
+
# on each row in a statement or on the statement itself. Possible
|
37
|
+
# values are <tt>:row</tt> and <tt>:statement</tt>, with
|
38
|
+
# <tt>:statement</tt> being the default.
|
39
|
+
# * <tt>:args</tt> - if the trigger function requires any
|
40
|
+
# arguments then this is the place to let everyone know about it.
|
41
|
+
#
|
42
|
+
# ==== Example
|
43
|
+
#
|
44
|
+
# ### ruby
|
45
|
+
# create_trigger(
|
46
|
+
# 'willie_nelsons_trigger',
|
47
|
+
# :before,
|
48
|
+
# :update,
|
49
|
+
# { :nylon => :guitar },
|
50
|
+
# 'strum_trigger',
|
51
|
+
# :for_each => :row
|
52
|
+
# )
|
53
|
+
# # => CREATE TRIGGER "willie_nelsons_trigger" BEFORE UPDATE
|
54
|
+
# # ON "nylon"."guitar" FOR EACH ROW EXECUTE PROCEDURE "test_trigger"();
|
55
|
+
def create_trigger(name, called, events, table, function, options = {})
|
56
|
+
execute PostgreSQLTriggerDefinition.new(self, name, called, events, table, function, options).to_s
|
57
|
+
end
|
58
|
+
|
59
|
+
# Drops a trigger.
|
60
|
+
#
|
61
|
+
# ==== Options
|
62
|
+
#
|
63
|
+
# * <tt>:if_exists</tt> - adds IF EXISTS.
|
64
|
+
# * <tt>:cascade</tt> - cascades changes down to objects referring
|
65
|
+
# to the trigger.
|
66
|
+
def drop_trigger(name, table, options = {})
|
67
|
+
sql = 'DROP TRIGGER '
|
68
|
+
sql << 'IF EXISTS ' if options[:if_exists]
|
69
|
+
sql << "#{quote_generic(name)} ON #{quote_table_name(table)}"
|
70
|
+
sql << ' CASCADE' if options[:cascade]
|
71
|
+
execute sql
|
72
|
+
end
|
73
|
+
|
74
|
+
# Renames a trigger.
|
75
|
+
def rename_trigger(name, table, new_name, options = {})
|
76
|
+
execute "ALTER TRIGGER #{quote_generic(name)} ON #{quote_table_name(table)} RENAME TO #{quote_generic(new_name)}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Creates a PostgreSQL trigger definition. This class isn't really
|
81
|
+
# meant to be used directly. You'd be better off sticking to
|
82
|
+
# PostgreSQLAdapter#create_trigger. Honestly.
|
83
|
+
class PostgreSQLTriggerDefinition
|
84
|
+
attr_accessor :base, :name, :called, :events, :table, :function, :options
|
85
|
+
|
86
|
+
def initialize(base, name, called, events, table, function, options = {}) #:nodoc:
|
87
|
+
assert_valid_called(called)
|
88
|
+
assert_valid_events(events)
|
89
|
+
assert_valid_for_each(options[:for_each])
|
90
|
+
|
91
|
+
@base, @name, @events, @called, @table, @function, @options =
|
92
|
+
base, name, events, called, table, function, options
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_sql #:nodoc:
|
96
|
+
sql = "CREATE TRIGGER #{base.quote_generic(name)} #{called.to_s.upcase} "
|
97
|
+
sql << Array(events).collect { |e| e.to_s.upcase }.join(' OR ')
|
98
|
+
sql << " OF " << Array(options[:of]).collect { |o| base.quote_generic(o) }.join(', ') if options[:of].present?
|
99
|
+
sql << " ON #{base.quote_table_name(table)}"
|
100
|
+
sql << " FOR EACH #{options[:for_each].to_s.upcase}" if options[:for_each]
|
101
|
+
sql << " EXECUTE PROCEDURE #{base.quote_function(function)}(#{options[:args]})"
|
102
|
+
sql
|
103
|
+
end
|
104
|
+
alias :to_s :to_sql
|
105
|
+
|
106
|
+
private
|
107
|
+
CALLED_TYPES = %w{ before after }.freeze
|
108
|
+
EVENT_TYPES = %w{ insert update delete }.freeze
|
109
|
+
FOR_EACH_TYPES = %w{ row statement }.freeze
|
110
|
+
|
111
|
+
def assert_valid_called(c) #:nodoc:
|
112
|
+
if !CALLED_TYPES.include?(c.to_s.downcase)
|
113
|
+
raise ActiveRecord::InvalidTriggerCallType.new(c)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def assert_valid_events(events) #:nodoc:
|
118
|
+
check_events = Array(events).collect(&:to_s) - EVENT_TYPES
|
119
|
+
if !check_events.empty?
|
120
|
+
raise ActiveRecord::InvalidTriggerEvent.new(check_events)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def assert_valid_for_each(f) #:nodoc:
|
125
|
+
if !FOR_EACH_TYPES.include?(f.to_s.downcase)
|
126
|
+
raise ActiveRecord::InvalidTriggerForEach.new(f)
|
127
|
+
end unless f.nil?
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
require 'active_record/connection_adapters/postgresql_adapter'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
module ConnectionAdapters
|
6
|
+
class PostgreSQLAdapter < AbstractAdapter
|
7
|
+
# Returns an Array of available languages.
|
8
|
+
def types(name = nil)
|
9
|
+
query(%{SELECT typname FROM pg_type}, name).map { |row| row[0] }
|
10
|
+
end
|
11
|
+
|
12
|
+
def type_exists?(name)
|
13
|
+
types.include?(name.to_s)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
|
2
|
+
require 'active_record/connection_adapters/postgresql_adapter'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
module ConnectionAdapters
|
6
|
+
class PostgreSQLAdapter < AbstractAdapter
|
7
|
+
# Creates a new PostgreSQL view.
|
8
|
+
#
|
9
|
+
# +name+ is the name of the view. View quoting works the same as
|
10
|
+
# table quoting, so you can use PostgreSQLAdapter#with_schema and
|
11
|
+
# friends. See PostgreSQLAdapter#with_schema and
|
12
|
+
# PostgreSQLAdapter#quote_table_name for details.
|
13
|
+
#
|
14
|
+
# +query+ is the SELECT query to use for the view. This is just
|
15
|
+
# a straight-up String, so quoting rules will not apply.
|
16
|
+
#
|
17
|
+
# Note that you can grant privileges on views using the
|
18
|
+
# grant_view_privileges method and revoke them using
|
19
|
+
# revoke_view_privileges.
|
20
|
+
#
|
21
|
+
# ==== Options
|
22
|
+
#
|
23
|
+
# * <tt>:replace</tt> - adds a REPLACE clause, as in "CREATE OR
|
24
|
+
# REPLACE".
|
25
|
+
# * <tt>:temporary</tt> - adds a TEMPORARY clause.
|
26
|
+
# * <tt>:columns</tt> - you can rename the output columns as
|
27
|
+
# necessary. Note that this can be an Array and that it must be
|
28
|
+
# the same length as the number of output columns created by
|
29
|
+
# +query+.
|
30
|
+
#
|
31
|
+
# ==== Examples
|
32
|
+
#
|
33
|
+
# ### ruby
|
34
|
+
# create_view(:foo_view, 'SELECT * FROM bar')
|
35
|
+
# # => CREATE VIEW "foo_view" AS SELECT * FROM bar;
|
36
|
+
#
|
37
|
+
# create_view(
|
38
|
+
# { :geospatial => :foo_view },
|
39
|
+
# 'SELECT * FROM bar',
|
40
|
+
# :columns => [ :id, :name, :the_geom ]
|
41
|
+
# )
|
42
|
+
# # => CREATE VIEW "geospatial"."foo_view" ("id", "name", "the_geom") AS SELECT * FROM bar;
|
43
|
+
def create_view(name, query, options = {})
|
44
|
+
execute PostgreSQLViewDefinition.new(self, name, query, options).to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
# Drops a view.
|
48
|
+
#
|
49
|
+
# ==== Options
|
50
|
+
#
|
51
|
+
# * <tt>:if_exists</tt> - adds IF EXISTS.
|
52
|
+
# * <tt>:cascade</tt> - adds CASCADE.
|
53
|
+
def drop_view(name, options = {})
|
54
|
+
sql = 'DROP VIEW '
|
55
|
+
sql << 'IF EXISTS ' if options[:if_exists]
|
56
|
+
sql << Array(name).collect { |v| quote_view_name(v) }.join(', ')
|
57
|
+
sql << ' CASCADE' if options[:cascade]
|
58
|
+
execute sql
|
59
|
+
end
|
60
|
+
|
61
|
+
# Renames a view.
|
62
|
+
def rename_view(name, new_name, options = {})
|
63
|
+
execute "ALTER TABLE #{quote_view_name(name)} RENAME TO #{quote_generic_ignore_schema(new_name)}"
|
64
|
+
end
|
65
|
+
|
66
|
+
# Change the ownership of a view.
|
67
|
+
def alter_view_owner(name, role, options = {})
|
68
|
+
execute "ALTER TABLE #{quote_view_name(name)} OWNER TO #{quote_role(role)}"
|
69
|
+
end
|
70
|
+
|
71
|
+
# Alter a view's schema.
|
72
|
+
def alter_view_schema(name, schema, options = {})
|
73
|
+
execute "ALTER TABLE #{quote_view_name(name)} SET SCHEMA #{quote_schema(schema)}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Creates a PostgreSQL view definition. This class isn't really meant
|
78
|
+
# to be used directly. Instead, see PostgreSQLAdapter#create_view
|
79
|
+
# for usage.
|
80
|
+
class PostgreSQLViewDefinition
|
81
|
+
attr_accessor :base, :name, :query, :options
|
82
|
+
|
83
|
+
def initialize(base, name, query, options = {}) #:nodoc:
|
84
|
+
@base, @name, @query, @options = base, name, query, options
|
85
|
+
end
|
86
|
+
|
87
|
+
def to_sql #:nodoc:
|
88
|
+
sql = 'CREATE '
|
89
|
+
sql << 'OR REPLACE ' if options[:replace]
|
90
|
+
sql << 'TEMPORARY ' if options[:temporary]
|
91
|
+
sql << "VIEW #{base.quote_view_name(name)} "
|
92
|
+
if options[:columns]
|
93
|
+
sql << '(' << Array(options[:columns]).collect do |c|
|
94
|
+
base.quote_column_name(c)
|
95
|
+
end.join(', ') << ') '
|
96
|
+
end
|
97
|
+
sql << "AS #{query}"
|
98
|
+
sql
|
99
|
+
end
|
100
|
+
alias :to_s :to_sql
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{postgresql-extensions}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["J Smith"]
|
12
|
+
s.date = %q{2010-11-30}
|
13
|
+
s.description = %q{A whole bunch of extensions the Rails PostgreSQL adapter.}
|
14
|
+
s.email = %q{code@zoocasa.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
"README",
|
20
|
+
"Rakefile",
|
21
|
+
"lib/postgresql_adapter_extensions.rb",
|
22
|
+
"lib/postgresql_constraints.rb",
|
23
|
+
"lib/postgresql_functions.rb",
|
24
|
+
"lib/postgresql_geometry.rb",
|
25
|
+
"lib/postgresql_indexes.rb",
|
26
|
+
"lib/postgresql_languages.rb",
|
27
|
+
"lib/postgresql_permissions.rb",
|
28
|
+
"lib/postgresql_rules.rb",
|
29
|
+
"lib/postgresql_schemas.rb",
|
30
|
+
"lib/postgresql_sequences.rb",
|
31
|
+
"lib/postgresql_tables.rb",
|
32
|
+
"lib/postgresql_triggers.rb",
|
33
|
+
"lib/postgresql_views.rb"
|
34
|
+
]
|
35
|
+
s.homepage = %q{http://github.com/zoocasa/postgresql-extensions}
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = %q{1.3.7}
|
38
|
+
s.summary = %q{A whole bunch of extensions the Rails PostgreSQL adapter.}
|
39
|
+
|
40
|
+
if s.respond_to? :specification_version then
|
41
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
42
|
+
s.specification_version = 3
|
43
|
+
|
44
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
45
|
+
else
|
46
|
+
end
|
47
|
+
else
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
$: << File.dirname(__FILE__)
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class AdapterExtensionTests < Test::Unit::TestCase
|
6
|
+
include PostgreSQLExtensionsTestHelper
|
7
|
+
|
8
|
+
def test_quote_table_name_with_schema_string
|
9
|
+
assert_equal(%{"foo"."bar"}, ARBC.quote_table_name('foo.bar'))
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_quote_table_name_with_schema_hash
|
13
|
+
assert_equal(%{"foo"."bar"}, ARBC.quote_table_name(:foo => :bar))
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_quote_table_name_with_current_schema
|
17
|
+
assert_equal(%{"foo"."bar"}, ARBC.with_schema(:foo) {
|
18
|
+
ARBC.quote_table_name(:bar)
|
19
|
+
})
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_quote_table_name_with_current_schema_ignored
|
23
|
+
assert_equal(%{"bar"}, ARBC.with_schema(:foo) {
|
24
|
+
ARBC.ignore_schema {
|
25
|
+
ARBC.quote_table_name(:bar)
|
26
|
+
}
|
27
|
+
})
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_quote_schema
|
31
|
+
assert_equal('PUBLIC', ARBC.quote_schema(:public))
|
32
|
+
assert_equal(%{"foo"}, ARBC.quote_schema(:foo))
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_other_quoting
|
36
|
+
assert_equal(%{"foo"}, ARBC.quote_generic(:foo))
|
37
|
+
assert_equal(%{"foo"}, ARBC.quote_role(:foo))
|
38
|
+
assert_equal(%{"foo"}, ARBC.quote_rule(:foo))
|
39
|
+
assert_equal(%{"foo"}, ARBC.quote_language(:foo))
|
40
|
+
assert_equal(%{"foo"}, ARBC.quote_sequence(:foo))
|
41
|
+
assert_equal(%{"foo"}, ARBC.quote_function(:foo))
|
42
|
+
assert_equal(%{"foo"}, ARBC.quote_view_name(:foo))
|
43
|
+
assert_equal(%{"foo"}, ARBC.quote_tablespace(:foo))
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
|
2
|
+
$: << File.dirname(__FILE__)
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class ConstraintTests < Test::Unit::TestCase
|
6
|
+
include PostgreSQLExtensionsTestHelper
|
7
|
+
|
8
|
+
def setup
|
9
|
+
clear_statements!
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_create_table_with_unique_constraint_on_table
|
13
|
+
Mig.create_table(:foo) do |t|
|
14
|
+
t.integer :bar_id
|
15
|
+
t.text :name
|
16
|
+
t.text :email
|
17
|
+
t.unique_constraint [ :id, :bar_id ]
|
18
|
+
t.unique_constraint [ :name, :email ], :tablespace => 'fubar'
|
19
|
+
end
|
20
|
+
|
21
|
+
assert_equal((<<-EOF).strip, statements[0])
|
22
|
+
CREATE TABLE "foo" (
|
23
|
+
"id" serial primary key,
|
24
|
+
"bar_id" integer,
|
25
|
+
"name" text,
|
26
|
+
"email" text,
|
27
|
+
UNIQUE ("id", "bar_id"),
|
28
|
+
UNIQUE ("name", "email") USING INDEX TABLESPACE "fubar"
|
29
|
+
)
|
30
|
+
EOF
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_create_table_with_unique_constraint_on_column
|
34
|
+
Mig.create_table(:foo) do |t|
|
35
|
+
t.integer :bar_id, :unique => true
|
36
|
+
end
|
37
|
+
|
38
|
+
assert_equal((<<-EOF).strip, statements[0])
|
39
|
+
CREATE TABLE "foo" (
|
40
|
+
"id" serial primary key,
|
41
|
+
"bar_id" integer,
|
42
|
+
UNIQUE ("bar_id")
|
43
|
+
)
|
44
|
+
EOF
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_add_unique_constraint
|
48
|
+
Mig.add_unique_constraint(:foo, :bar_id)
|
49
|
+
Mig.add_unique_constraint(
|
50
|
+
:foo,
|
51
|
+
:bar_id,
|
52
|
+
:tablespace => 'fubar',
|
53
|
+
:storage_parameters => 'FILLFACTOR=10',
|
54
|
+
:name => 'bar_id_unique'
|
55
|
+
)
|
56
|
+
|
57
|
+
assert_equal([
|
58
|
+
"ALTER TABLE \"foo\" ADD UNIQUE (\"bar_id\")",
|
59
|
+
"ALTER TABLE \"foo\" ADD CONSTRAINT \"bar_id_unique\" UNIQUE (\"bar_id\") WITH (FILLFACTOR=10) USING INDEX TABLESPACE \"fubar\""
|
60
|
+
], statements)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_add_foreign_key
|
64
|
+
Mig.add_foreign_key(:foo, :bar_id, :bar)
|
65
|
+
Mig.add_foreign_key(:foo, :bar_id, :bar, :ogc_fid, :name => 'bar_fk')
|
66
|
+
Mig.add_foreign_key(:foo, [ :one_id, :bar_id ], :bar, [ :one_id, :bar_id ], :match => 'full')
|
67
|
+
Mig.add_foreign_key(:foo, :bar_id, :bar, :on_delete => :cascade, :on_delete => :set_default)
|
68
|
+
Mig.add_foreign_key(:foo, :bar_id, :bar, :deferrable => :immediate)
|
69
|
+
|
70
|
+
assert_equal([
|
71
|
+
"ALTER TABLE \"foo\" ADD FOREIGN KEY (\"bar_id\") REFERENCES \"bar\"",
|
72
|
+
"ALTER TABLE \"foo\" ADD CONSTRAINT \"bar_fk\" FOREIGN KEY (\"bar_id\") REFERENCES \"bar\" (\"ogc_fid\")",
|
73
|
+
"ALTER TABLE \"foo\" ADD FOREIGN KEY (\"one_id\", \"bar_id\") REFERENCES \"bar\" (\"one_id\", \"bar_id\") MATCH FULL",
|
74
|
+
"ALTER TABLE \"foo\" ADD FOREIGN KEY (\"bar_id\") REFERENCES \"bar\" ON DELETE SET DEFAULT",
|
75
|
+
"ALTER TABLE \"foo\" ADD FOREIGN KEY (\"bar_id\") REFERENCES \"bar\" DEFERRABLE INITIALLY IMMEDIATE"
|
76
|
+
], statements)
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_drop_constraint
|
80
|
+
Mig.drop_constraint(:foo, :bar)
|
81
|
+
Mig.drop_constraint(:foo, :bar, :cascade => true)
|
82
|
+
|
83
|
+
assert_equal([
|
84
|
+
"ALTER TABLE \"foo\" DROP CONSTRAINT \"bar\"",
|
85
|
+
"ALTER TABLE \"foo\" DROP CONSTRAINT \"bar\" CASCADE"
|
86
|
+
], statements)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_add_check_constraint
|
90
|
+
Mig.add_check_constraint(:foo, 'length(name) < 100')
|
91
|
+
Mig.add_check_constraint(:foo, 'length(name) < 100', :name => 'name_length_check')
|
92
|
+
|
93
|
+
assert_equal([
|
94
|
+
"ALTER TABLE \"foo\" ADD CHECK (length(name) < 100)",
|
95
|
+
"ALTER TABLE \"foo\" ADD CONSTRAINT \"name_length_check\" CHECK (length(name) < 100)"
|
96
|
+
], statements)
|
97
|
+
end
|
98
|
+
end
|