db_leftovers 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/Changelog CHANGED
@@ -1,3 +1,14 @@
1
+ 1.6.0
2
+ -----
3
+
4
+ - Support foreign keys that are `DEFERRABLE INITIALLY DEFERRED` and
5
+ `DEFERRABLE INITIALLY IMMEDIATE`.
6
+
7
+ 1.5.0
8
+ -----
9
+
10
+ - Permit custom names for foreign keys.
11
+
1
12
  1.4.2
2
13
  -----
3
14
 
data/README.md CHANGED
@@ -79,6 +79,12 @@ Opts is a hash with the following possible keys:
79
79
  * `:set_null` Indicates that the foreign key should be set to null if the referenced row is deleted.
80
80
  * `:cascade` Indicates that the referencing row should be deleted if the referenced row is deleted.
81
81
 
82
+ * `:deferrable` Marks the constraint as deferrable. Accepts these values:
83
+
84
+ * `nil` Indicates the constraint is not deferrable (the default).
85
+ * `:immediate` Indicates the constraint is usually enforced immediately but can be deferred.
86
+ * `:deferred` Indicates the constraint is always enforced deferred.
87
+
82
88
  #### Examples
83
89
 
84
90
  foreign_key :books, :author_id, :authors, :id
@@ -89,7 +95,7 @@ With implicit column names:
89
95
  foreign_key :books, :authors
90
96
  foreign_key :books, :authors, :on_delete => :cascade
91
97
  foreign_key :books, :co_author_id, :authors
92
- foreign_key :books, :co_author_id, :authors, :on_delete => :cascade
98
+ foreign_key :books, :co_author_id, :authors, :on_delete => :cascade, :deferred => :immediate
93
99
 
94
100
  ### check(on\_table, constraint\_name, expression)
95
101
 
@@ -1,19 +1,21 @@
1
1
  module DBLeftovers
2
2
 
3
3
  class ForeignKey
4
- attr_accessor :constraint_name, :from_table, :from_column, :to_table, :to_column, :set_null, :cascade
4
+ attr_accessor :constraint_name, :from_table, :from_column, :to_table, :to_column, :set_null, :cascade, :deferrable_initially_immediate, :deferrable_initially_deferred
5
5
 
6
6
  def initialize(from_table, from_column, to_table, to_column, opts={})
7
7
  opts = {
8
+ :deferrable => nil,
8
9
  :on_delete => nil,
9
10
  :name => name_constraint(from_table, from_column)
10
11
  }.merge(opts)
11
12
  opts.keys.each do |k|
12
13
  raise "`:set_null => true` should now be `:on_delete => :set_null`" if k.to_s == 'set_null'
13
14
  raise "`:cascade => true` should now be `:on_delete => :cascade`" if k.to_s == 'cascade'
14
- raise "Unknown option: #{k}" unless [:on_delete, :name].include?(k)
15
+ raise "Unknown option: #{k}" unless [:on_delete, :name, :deferrable].include?(k)
15
16
  end
16
17
  raise "Unknown on_delete option: #{opts[:on_delete]}" unless [nil, :set_null, :cascade].include?(opts[:on_delete])
18
+ raise "Unknown deferrable option: #{opts[:deferrable]}" unless [nil, :immediate, :deferred].include?(opts[:deferrable])
17
19
  @constraint_name = opts[:name].to_s
18
20
  @from_table = from_table.to_s
19
21
  @from_column = from_column.to_s
@@ -21,9 +23,12 @@ module DBLeftovers
21
23
  @to_column = to_column.to_s
22
24
 
23
25
  @set_null = opts[:on_delete] == :set_null
24
- @cascade = opts[:on_delete] == :cascade
26
+ @cascade = opts[:on_delete] == :cascade
27
+ @deferrable_initially_immediate = opts[:deferrable] == :immediate
28
+ @deferrable_initially_deferred = opts[:deferrable] == :deferred
25
29
 
26
30
  raise "ON DELETE can't be both set_null and cascade" if @set_null and @cascade
31
+ raise "DEFERRABLE can't be both immediate and deferred" if @deferrable_initially_immediate and @deferrable_initially_deferred
27
32
  end
28
33
 
29
34
  def equals(other)
@@ -33,11 +38,24 @@ module DBLeftovers
33
38
  other.to_table == to_table and
34
39
  other.to_column == to_column and
35
40
  other.set_null == set_null and
36
- other.cascade == cascade
41
+ other.cascade == cascade and
42
+ other.deferrable_initially_immediate == deferrable_initially_immediate and
43
+ other.deferrable_initially_deferred == deferrable_initially_deferred
37
44
  end
38
45
 
39
46
  def to_s
40
- "<#{@constraint_name}: from #{@from_table}.#{@from_column} to #{@to_table}.#{@to_column} #{if @set_null; "ON DELETE SET NULL "; elsif @cascade; "ON DELETE CASCADE "; else ""; end}>"
47
+ [
48
+ "<#{@constraint_name}: from #{@from_table}.#{@from_column} to #{@to_table}.#{@to_column}",
49
+ if @set_null; "ON DELETE SET NULL"
50
+ elsif @cascade; "ON DELETE CASCADE"
51
+ else; nil
52
+ end,
53
+ if @deferrable_initially_immediate; "DEFERRABLE INITIALLY IMMEDIATE"
54
+ elsif @deferrable_initially_deferred; "DEFERRABLE INITIALLY DEFERRED"
55
+ else; nil
56
+ end,
57
+ ">"
58
+ ].compact.join(" ")
41
59
  end
42
60
 
43
61
  def name_constraint(from_table, from_column)
@@ -37,13 +37,16 @@ module DBLeftovers
37
37
  end
38
38
 
39
39
  def execute_add_foreign_key(fk)
40
- on_delete = "ON DELETE CASCADE" if fk.cascade
40
+ on_delete = "ON DELETE CASCADE" if fk.cascade
41
41
  on_delete = "ON DELETE SET NULL" if fk.set_null
42
+ deferrable = "DEFERRABLE INITIALLY DEFERRED" if fk.deferrable_initially_deferred
43
+ deferrable = "DEFERRABLE INITIALLY IMMEDIATE" if fk.deferrable_initially_immediate
42
44
  execute_sql %{ALTER TABLE #{fk.from_table}
43
45
  ADD CONSTRAINT #{fk.constraint_name}
44
46
  FOREIGN KEY (#{fk.from_column})
45
47
  REFERENCES #{fk.to_table} (#{fk.to_column})
46
- #{on_delete}}
48
+ #{on_delete}
49
+ #{deferrable}}
47
50
  end
48
51
 
49
52
  def execute_drop_foreign_key(constraint_name, from_table, from_column)
@@ -70,7 +70,9 @@ module DBLeftovers
70
70
  a1.attname AS from_column,
71
71
  t2.relname AS to_table,
72
72
  a2.attname AS to_column,
73
- c.confdeltype
73
+ c.confdeltype,
74
+ c.condeferrable AS deferrable,
75
+ c.condeferred AS deferred
74
76
  FROM pg_catalog.pg_constraint c,
75
77
  pg_catalog.pg_class t1,
76
78
  pg_catalog.pg_class t2,
@@ -94,14 +96,20 @@ module DBLeftovers
94
96
  AND pg_catalog.pg_table_is_visible(t1.oid)
95
97
  AND pg_catalog.pg_table_is_visible(t2.oid)
96
98
  EOQ
97
- @conn.select_rows(sql).each do |constr_name, from_table, from_column, to_table, to_column, del_type|
99
+ @conn.select_rows(sql).each do |constr_name, from_table, from_column, to_table, to_column, del_type, deferrable, deferred|
98
100
  del_type = case del_type
99
101
  when 'a'; nil
100
102
  when 'c'; :cascade
101
103
  when 'n'; :set_null
102
104
  else; raise "Unknown del type: #{del_type}"
103
105
  end
104
- ret[constr_name] = ForeignKey.new(from_table, from_column, to_table, to_column, :name => constr_name, :on_delete => del_type)
106
+ deferrable = deferrable == 't'
107
+ deferred = deferred == 't'
108
+ defer_type = if deferrable and deferred; :deferred
109
+ elsif deferrable; :immediate
110
+ else; nil
111
+ end
112
+ ret[constr_name] = ForeignKey.new(from_table, from_column, to_table, to_column, :name => constr_name, :on_delete => del_type, :deferrable => defer_type)
105
113
  end
106
114
  return ret
107
115
  end
@@ -1,3 +1,3 @@
1
1
  module DbLeftovers
2
- VERSION = '1.5.0'
2
+ VERSION = '1.6.0'
3
3
  end
@@ -72,9 +72,9 @@ describe DBLeftovers do
72
72
  it "should create foreign keys on an empty database" do
73
73
  @db.starts_with
74
74
  DBLeftovers::Definition.define :db_interface => @db do
75
- foreign_key :books, :shelf_id, :shelves
75
+ foreign_key :books, :shelf_id, :shelves, :deferrable => :deferred
76
76
  foreign_key :books, :publisher_id, :publishers, :id, :on_delete => :set_null
77
- foreign_key :books, :author_id, :authors, :id, :on_delete => :cascade
77
+ foreign_key :books, :author_id, :authors, :id, :on_delete => :cascade, :deferrable => :immediate
78
78
  end
79
79
  @db.sqls.should have(3).items
80
80
  @db.should have_seen_sql <<-EOQ
@@ -82,6 +82,7 @@ describe DBLeftovers do
82
82
  ADD CONSTRAINT fk_books_shelf_id
83
83
  FOREIGN KEY (shelf_id)
84
84
  REFERENCES shelves (id)
85
+ DEFERRABLE INITIALLY DEFERRED
85
86
  EOQ
86
87
  @db.should have_seen_sql <<-EOQ
87
88
  ALTER TABLE books
@@ -96,6 +97,7 @@ describe DBLeftovers do
96
97
  FOREIGN KEY (author_id)
97
98
  REFERENCES authors (id)
98
99
  ON DELETE CASCADE
100
+ DEFERRABLE INITIALLY IMMEDIATE
99
101
  EOQ
100
102
  end
101
103
 
@@ -105,9 +107,9 @@ describe DBLeftovers do
105
107
  @db.starts_with
106
108
  DBLeftovers::Definition.define :db_interface => @db do
107
109
  table :books do
108
- foreign_key :shelf_id, :shelves
110
+ foreign_key :shelf_id, :shelves, :deferrable => :deferred
109
111
  foreign_key :publisher_id, :publishers, :id, :on_delete => :set_null
110
- foreign_key :author_id, :authors, :id, :on_delete => :cascade
112
+ foreign_key :author_id, :authors, :id, :on_delete => :cascade, :deferrable => :immediate
111
113
  end
112
114
  end
113
115
  @db.sqls.should have(3).items
@@ -116,6 +118,7 @@ describe DBLeftovers do
116
118
  ADD CONSTRAINT fk_books_shelf_id
117
119
  FOREIGN KEY (shelf_id)
118
120
  REFERENCES shelves (id)
121
+ DEFERRABLE INITIALLY DEFERRED
119
122
  EOQ
120
123
  @db.should have_seen_sql <<-EOQ
121
124
  ALTER TABLE books
@@ -130,6 +133,7 @@ describe DBLeftovers do
130
133
  FOREIGN KEY (author_id)
131
134
  REFERENCES authors (id)
132
135
  ON DELETE CASCADE
136
+ DEFERRABLE INITIALLY IMMEDIATE
133
137
  EOQ
134
138
  end
135
139
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: db_leftovers
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.6.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -112,7 +112,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
112
112
  version: '0'
113
113
  segments:
114
114
  - 0
115
- hash: -363906017218431327
115
+ hash: 3317985398985958458
116
116
  required_rubygems_version: !ruby/object:Gem::Requirement
117
117
  none: false
118
118
  requirements: