db_leftovers 1.5.0 → 1.6.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.
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: