rein 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 174a8d4fd2ac014ff07be51f2066f24031093af5
4
- data.tar.gz: a87d03529fbac3e218d7f9a8bb525e168ecd9942
3
+ metadata.gz: 4c092acce07a6896465dbff427aa22bbac84a4b9
4
+ data.tar.gz: 7cdc3ad273b86b172930826e82264d29c938326a
5
5
  SHA512:
6
- metadata.gz: a1a4ee06b5194406e7505c727851d9d8d1d2e5e89e01bd0f4f4a4e27beca20a232b7ec9cad514f2b1f3eecf91e5debe31268a69e4c92a5619ea283915b6e5f1e
7
- data.tar.gz: 43fac121fcf44b69e6ff326cf6a3b291b4c534ee4c2af0aa6b5e5a8cfa274795d6c34abdbe55045044c8e7ba8cc33cef7f4a3003e0009bb540f15344e7ef1545
6
+ metadata.gz: 591a05bf15e0857934e00ec98cc91644fed9d5ba5d793dfd8216e9cf51b5ecf797e16f7e78cd43aaef887299b079b7d0c2702c4210f742b38e385c604083b378
7
+ data.tar.gz: cd84ac0a68c41f37969debd3c719e502750f002725287f72a2e829bcce58a998239935d503144553d7d5ab48444c2675a335913e72472b36754aa95532f2f7bb
@@ -1,5 +1,8 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.3.0
4
+ - Add unique constraint.
5
+
3
6
  ## 3.2.0
4
7
  - Add match constraint.
5
8
  - Fix the rollback of change view migrations.
data/README.md CHANGED
@@ -15,27 +15,26 @@ can easily tame the data in your database.
15
15
  All methods in the DSL are automatically *reversible*, so you can take
16
16
  advantage of reversible Rails migrations.
17
17
 
18
- ## Table of contents
19
-
20
- * [Rein](#rein)
21
- * [Table of contents](#table-of-contents)
22
- * [Getting started](#getting-started)
23
- * [Constraint types](#constraint-types)
24
- * [Foreign key constraints](#foreign-key-constraints)
25
- * [Inclusion constraints](#inclusion-constraints)
26
- * [Length constraints](#length-constraints)
27
- * [Match constraints](#match-constraints)
28
- * [Numericality constraints](#numericality-constraints)
29
- * [Presence constraints](#presence-constraints)
30
- * [Null constraints](#null-constraints)
31
- * [Data types](#data-types)
32
- * [Enumerated types](#enumerated-types)
33
- * [Views](#views)
34
- * [Schemas](#schemas)
35
- * [Example](#example)
36
- * [License](#license)
37
-
38
- ## Getting started
18
+ ## Table of Contents
19
+
20
+ * [Getting Started](#getting-started)
21
+ * [Constraint Types](#constraint-types)
22
+ * [Foreign Key Constraints](#foreign-key-constraints)
23
+ * [Unique Constraints](#unique-constraints)
24
+ * [Inclusion Constraints](#inclusion-constraints)
25
+ * [Length Constraints](#length-constraints)
26
+ * [Match Constraints](#match-constraints)
27
+ * [Numericality Constraints](#numericality-constraints)
28
+ * [Presence Constraints](#presence-constraints)
29
+ * [Null Constraints](#null-constraints)
30
+ * [Data Types](#data-types)
31
+ * [Enumerated Types](#enumerated-types)
32
+ * [Views](#views)
33
+ * [Schemas](#schemas)
34
+ * [Examples](#examples)
35
+ * [License](#license)
36
+
37
+ ## Getting Started
39
38
 
40
39
  Install the gem:
41
40
 
@@ -58,9 +57,9 @@ class CreateAuthorsTable < ActiveRecord::Migration
58
57
  end
59
58
  ```
60
59
 
61
- ## Constraint types
60
+ ## Constraint Types
62
61
 
63
- ### Foreign key constraints
62
+ ### Foreign Key Constraints
64
63
 
65
64
  A foreign key constraint specifies that the values in a column must match the
66
65
  values appearing in some row of another table.
@@ -113,7 +112,53 @@ To remove a foreign key constraint:
113
112
  remove_foreign_key_constraint :books, :authors
114
113
  ```
115
114
 
116
- ### Inclusion constraints
115
+ ### Unique Constraints
116
+
117
+ A unique constraint specifies that certain columns in a table must be unique.
118
+
119
+ For example, all the books should have unique ISBNs:
120
+
121
+ ```ruby
122
+ add_unique_constraint :books, :isbn
123
+ ```
124
+
125
+ By default, the database checks unique constraints immediately (i.e. as soon as
126
+ a record is created or updated). If a record with a duplicate value exists,
127
+ then the database will raise an error.
128
+
129
+ Sometimes it is necessary to wait until the end of a transaction to do the
130
+ checking (e.g. maybe you want to swap the ISBNs for two books). To do so, you
131
+ need to tell the database to *defer* checking the constraint until the end of
132
+ the current transaction:
133
+
134
+ ```sql
135
+ BEGIN;
136
+ SET CONSTRAINTS books_isbn_unique DEFERRED;
137
+ UPDATE books SET isbn = 'foo' WHERE id = 1;
138
+ UPDATE books SET isbn = 'bar' WHERE id = 2;
139
+ COMMIT;
140
+ ```
141
+
142
+ This [blog
143
+ post](https://hashrocket.com/blog/posts/deferring-database-constraints) offers
144
+ a good explanation of how to do this in a Rails app when using the
145
+ `acts_as_list` plugin.
146
+
147
+ If you *always* want to defer checking a unique constraint, then you can set
148
+ the `deferred` option to `true`:
149
+
150
+ ```ruby
151
+ add_unique_constraint :books, :isbn, deferred: true
152
+ ```
153
+
154
+ If you really don't want the ability to optionally defer a unique constraint in
155
+ a transaction, then you can set the `deferrable` option to `false`:
156
+
157
+ ```ruby
158
+ add_unique_constraint :authors, :name, deferrable: false
159
+ ```
160
+
161
+ ### Inclusion Constraints
117
162
 
118
163
  An inclusion constraint specifies the possible values that a column value can
119
164
  take.
@@ -148,7 +193,7 @@ add_inclusion_constraint :books, :state,
148
193
  name: "books_state_is_valid"
149
194
  ```
150
195
 
151
- ### Length constraints
196
+ ### Length Constraints
152
197
 
153
198
  A length constraint specifies the range of values that the length of a string
154
199
  column value can take.
@@ -196,7 +241,7 @@ To remove a length constraint:
196
241
  remove_length_constraint :books, :call_number
197
242
  ```
198
243
 
199
- ### Match constraints
244
+ ### Match Constraints
200
245
 
201
246
  A match constraint ensures that a string column value matches (or does not match)
202
247
  a POSIX-style regular expression.
@@ -227,7 +272,7 @@ To remove a match constraint:
227
272
  remove_match_constraint :books, :title
228
273
  ```
229
274
 
230
- ### Numericality constraints
275
+ ### Numericality Constraints
231
276
 
232
277
  A numericality constraint specifies the range of values that a numeric column
233
278
  value can take.
@@ -275,7 +320,7 @@ To remove a numericality constraint:
275
320
  remove_numericality_constraint :books, :publication_month
276
321
  ```
277
322
 
278
- ### Presence constraints
323
+ ### Presence Constraints
279
324
 
280
325
  A presence constraint ensures that a string column value is non-empty.
281
326
 
@@ -305,7 +350,7 @@ To remove a presence constraint:
305
350
  remove_presence_constraint :books, :title
306
351
  ```
307
352
 
308
- ### Null constraints
353
+ ### Null Constraints
309
354
 
310
355
  A null constraint ensures that a column does *not* contain a null value. This
311
356
  is the same as adding `NOT NULL` to a column, the difference being that it can
@@ -324,9 +369,9 @@ To remove a null constraint:
324
369
  remove_null_constraint :books, :due_date
325
370
  ```
326
371
 
327
- ## Data types
372
+ ## Data Types
328
373
 
329
- ### Enumerated types
374
+ ### Enumerated Types
330
375
 
331
376
  An enum is a data type that represents a static, ordered set of values.
332
377
 
@@ -374,7 +419,7 @@ To drop a schema from the database:
374
419
  drop_schema :archive
375
420
  ```
376
421
 
377
- ## Example
422
+ ## Examples
378
423
 
379
424
  Let's have a look at some example migrations to constrain database values for
380
425
  our simple library application:
@@ -1,15 +1,16 @@
1
- require "active_record"
2
- require "rein/constraint/foreign_key"
3
- require "rein/constraint/inclusion"
4
- require "rein/constraint/length"
5
- require "rein/constraint/match"
6
- require "rein/constraint/null"
7
- require "rein/constraint/numericality"
8
- require "rein/constraint/presence"
9
- require "rein/constraint/primary_key"
10
- require "rein/schema"
11
- require "rein/type/enum"
12
- require "rein/view"
1
+ require 'active_record'
2
+ require 'rein/constraint/foreign_key'
3
+ require 'rein/constraint/inclusion'
4
+ require 'rein/constraint/length'
5
+ require 'rein/constraint/match'
6
+ require 'rein/constraint/null'
7
+ require 'rein/constraint/numericality'
8
+ require 'rein/constraint/presence'
9
+ require 'rein/constraint/primary_key'
10
+ require 'rein/constraint/unique'
11
+ require 'rein/schema'
12
+ require 'rein/type/enum'
13
+ require 'rein/view'
13
14
 
14
15
  module ActiveRecord
15
16
  class Migration # :nodoc:
@@ -21,6 +22,7 @@ module ActiveRecord
21
22
  include Rein::Constraint::Numericality
22
23
  include Rein::Constraint::Presence
23
24
  include Rein::Constraint::PrimaryKey
25
+ include Rein::Constraint::Unique
24
26
  include Rein::Schema
25
27
  include Rein::Type::Enum
26
28
  include Rein::View
@@ -1,5 +1,5 @@
1
- require "active_support/inflector"
2
- require "rein/util"
1
+ require 'active_support/inflector'
2
+ require 'rein/util'
3
3
 
4
4
  module Rein
5
5
  module Constraint
@@ -7,14 +7,14 @@ module Rein
7
7
  module ForeignKey
8
8
  def add_foreign_key_constraint(*args)
9
9
  reversible do |dir|
10
- dir.up { _add_foreign_key_constraint(*args) }
10
+ dir.up do _add_foreign_key_constraint(*args) end
11
11
  dir.down { _remove_foreign_key_constraint(*args) }
12
12
  end
13
13
  end
14
14
 
15
15
  def remove_foreign_key_constraint(*args)
16
16
  reversible do |dir|
17
- dir.up { _remove_foreign_key_constraint(*args) }
17
+ dir.up do _remove_foreign_key_constraint(*args) end
18
18
  dir.down { _add_foreign_key_constraint(*args) }
19
19
  end
20
20
  end
@@ -23,8 +23,8 @@ module Rein
23
23
 
24
24
  def _add_foreign_key_constraint(referencing_table, referenced_table, options = {})
25
25
  referencing_attribute = (options[:referencing] || "#{referenced_table.to_s.singularize}_id").to_sym
26
- referenced_attribute = (options[:referenced] || "id").to_sym
27
- name = Util.constraint_name(referencing_table, referencing_attribute, "fk", options)
26
+ referenced_attribute = (options[:referenced] || 'id').to_sym
27
+ name = Util.constraint_name(referencing_table, referencing_attribute, 'fk', options)
28
28
  sql = "ALTER TABLE #{referencing_table}"
29
29
  sql << " ADD CONSTRAINT #{name}"
30
30
  sql << " FOREIGN KEY (#{referencing_attribute})"
@@ -37,18 +37,18 @@ module Rein
37
37
 
38
38
  def _remove_foreign_key_constraint(referencing_table, referenced_table, options = {})
39
39
  referencing_attribute = options[:referencing] || "#{referenced_table.to_s.singularize}_id".to_sym
40
- name = Util.constraint_name(referencing_table, referencing_attribute, "fk", options)
40
+ name = Util.constraint_name(referencing_table, referencing_attribute, 'fk', options)
41
41
  execute("ALTER TABLE #{referencing_table} DROP CONSTRAINT #{name}")
42
42
  remove_index(referencing_table, referencing_attribute) if options[:index] == true
43
43
  end
44
44
 
45
45
  def referential_action(action)
46
46
  case action.to_sym
47
- when :no_action then "NO ACTION"
48
- when :cascade then "CASCADE"
49
- when :restrict then "RESTRICT"
50
- when :set_null, :nullify then "SET NULL"
51
- when :set_default, :default then "SET DEFAULT"
47
+ when :no_action then 'NO ACTION'
48
+ when :cascade then 'CASCADE'
49
+ when :restrict then 'RESTRICT'
50
+ when :set_null, :nullify then 'SET NULL'
51
+ when :set_default, :default then 'SET DEFAULT'
52
52
  else raise "Unknown referential action '#{action}'"
53
53
  end
54
54
  end
@@ -1,4 +1,4 @@
1
- require "rein/util"
1
+ require 'rein/util'
2
2
 
3
3
  module Rein
4
4
  module Constraint
@@ -8,14 +8,14 @@ module Rein
8
8
 
9
9
  def add_inclusion_constraint(*args)
10
10
  reversible do |dir|
11
- dir.up { _add_inclusion_constraint(*args) }
11
+ dir.up do _add_inclusion_constraint(*args) end
12
12
  dir.down { _remove_inclusion_constraint(*args) }
13
13
  end
14
14
  end
15
15
 
16
16
  def remove_inclusion_constraint(*args)
17
17
  reversible do |dir|
18
- dir.up { _remove_inclusion_constraint(*args) }
18
+ dir.up do _remove_inclusion_constraint(*args) end
19
19
  dir.down { _add_inclusion_constraint(*args) }
20
20
  end
21
21
  end
@@ -23,14 +23,14 @@ module Rein
23
23
  private
24
24
 
25
25
  def _add_inclusion_constraint(table, attribute, options = {})
26
- name = Util.constraint_name(table, attribute, "inclusion", options)
27
- values = options[:in].map { |value| quote(value) }.join(", ")
26
+ name = Util.constraint_name(table, attribute, 'inclusion', options)
27
+ values = options[:in].map { |value| quote(value) }.join(', ')
28
28
  conditions = Util.conditions_with_if("#{attribute} IN (#{values})", options)
29
29
  execute("ALTER TABLE #{table} ADD CONSTRAINT #{name} CHECK (#{conditions})")
30
30
  end
31
31
 
32
32
  def _remove_inclusion_constraint(table, attribute, options = {})
33
- name = Util.constraint_name(table, attribute, "inclusion", options)
33
+ name = Util.constraint_name(table, attribute, 'inclusion', options)
34
34
  execute("ALTER TABLE #{table} DROP CONSTRAINT #{name}")
35
35
  end
36
36
  end
@@ -1,4 +1,4 @@
1
- require "rein/util"
1
+ require 'rein/util'
2
2
 
3
3
  module Rein
4
4
  module Constraint
@@ -15,14 +15,14 @@ module Rein
15
15
 
16
16
  def add_length_constraint(*args)
17
17
  reversible do |dir|
18
- dir.up { _add_length_constraint(*args) }
18
+ dir.up do _add_length_constraint(*args) end
19
19
  dir.down { _remove_length_constraint(*args) }
20
20
  end
21
21
  end
22
22
 
23
23
  def remove_length_constraint(*args)
24
24
  reversible do |dir|
25
- dir.up { _remove_length_constraint(*args) }
25
+ dir.up do _remove_length_constraint(*args) end
26
26
  dir.down { _add_length_constraint(*args) }
27
27
  end
28
28
  end
@@ -30,18 +30,18 @@ module Rein
30
30
  private
31
31
 
32
32
  def _add_length_constraint(table, attribute, options = {})
33
- name = Util.constraint_name(table, attribute, "length", options)
33
+ name = Util.constraint_name(table, attribute, 'length', options)
34
34
  attribute_length = "length(#{attribute})"
35
- conditions = OPERATORS.slice(*options.keys).map do |key, operator|
35
+ conditions = OPERATORS.slice(*options.keys).map { |key, operator|
36
36
  value = options[key]
37
- [attribute_length, operator, value].join(" ")
38
- end.join(" AND ")
37
+ [attribute_length, operator, value].join(' ')
38
+ }.join(' AND ')
39
39
  conditions = Util.conditions_with_if(conditions, options)
40
40
  execute("ALTER TABLE #{table} ADD CONSTRAINT #{name} CHECK (#{conditions})")
41
41
  end
42
42
 
43
43
  def _remove_length_constraint(table, attribute, options = {})
44
- name = Util.constraint_name(table, attribute, "length", options)
44
+ name = Util.constraint_name(table, attribute, 'length', options)
45
45
  execute("ALTER TABLE #{table} DROP CONSTRAINT #{name}")
46
46
  end
47
47
  end
@@ -1,4 +1,4 @@
1
- require "rein/util"
1
+ require 'rein/util'
2
2
 
3
3
  module Rein
4
4
  module Constraint
@@ -13,14 +13,14 @@ module Rein
13
13
 
14
14
  def add_match_constraint(*args)
15
15
  reversible do |dir|
16
- dir.up { _add_match_constraint(*args) }
16
+ dir.up do _add_match_constraint(*args) end
17
17
  dir.down { _remove_match_constraint(*args) }
18
18
  end
19
19
  end
20
20
 
21
21
  def remove_match_constraint(*args)
22
22
  reversible do |dir|
23
- dir.up { _remove_match_constraint(*args) }
23
+ dir.up do _remove_match_constraint(*args) end
24
24
  dir.down { _add_match_constraint(*args) }
25
25
  end
26
26
  end
@@ -28,17 +28,17 @@ module Rein
28
28
  private
29
29
 
30
30
  def _add_match_constraint(table, attribute, options = {})
31
- name = Util.constraint_name(table, attribute, "match", options)
32
- conditions = OPERATORS.slice(*options.keys).map do |key, operator|
31
+ name = Util.constraint_name(table, attribute, 'match', options)
32
+ conditions = OPERATORS.slice(*options.keys).map { |key, operator|
33
33
  value = options[key]
34
- [attribute, operator, "'#{value}'"].join(" ")
35
- end.join(" AND ")
34
+ [attribute, operator, "'#{value}'"].join(' ')
35
+ }.join(' AND ')
36
36
  conditions = Util.conditions_with_if(conditions, options)
37
37
  execute("ALTER TABLE #{table} ADD CONSTRAINT #{name} CHECK (#{conditions})")
38
38
  end
39
39
 
40
40
  def _remove_match_constraint(table, attribute, options = {})
41
- name = Util.constraint_name(table, attribute, "match", options)
41
+ name = Util.constraint_name(table, attribute, 'match', options)
42
42
  execute("ALTER TABLE #{table} DROP CONSTRAINT #{name}")
43
43
  end
44
44
  end
@@ -1,4 +1,4 @@
1
- require "rein/util"
1
+ require 'rein/util'
2
2
 
3
3
  module Rein
4
4
  module Constraint
@@ -8,14 +8,14 @@ module Rein
8
8
 
9
9
  def add_null_constraint(*args)
10
10
  reversible do |dir|
11
- dir.up { _add_null_constraint(*args) }
11
+ dir.up do _add_null_constraint(*args) end
12
12
  dir.down { _remove_null_constraint(*args) }
13
13
  end
14
14
  end
15
15
 
16
16
  def remove_null_constraint(*args)
17
17
  reversible do |dir|
18
- dir.up { _remove_null_constraint(*args) }
18
+ dir.up do _remove_null_constraint(*args) end
19
19
  dir.down { _add_null_constraint(*args) }
20
20
  end
21
21
  end
@@ -23,13 +23,13 @@ module Rein
23
23
  private
24
24
 
25
25
  def _add_null_constraint(table, attribute, options = {})
26
- name = Util.constraint_name(table, attribute, "null", options)
26
+ name = Util.constraint_name(table, attribute, 'null', options)
27
27
  conditions = Util.conditions_with_if("#{attribute} IS NOT NULL", options)
28
28
  execute("ALTER TABLE #{table} ADD CONSTRAINT #{name} CHECK (#{conditions})")
29
29
  end
30
30
 
31
31
  def _remove_null_constraint(table, attribute, options = {})
32
- name = Util.constraint_name(table, attribute, "null", options)
32
+ name = Util.constraint_name(table, attribute, 'null', options)
33
33
  execute("ALTER TABLE #{table} DROP CONSTRAINT #{name}")
34
34
  end
35
35
  end
@@ -1,4 +1,4 @@
1
- require "rein/util"
1
+ require 'rein/util'
2
2
 
3
3
  module Rein
4
4
  module Constraint
@@ -15,14 +15,14 @@ module Rein
15
15
 
16
16
  def add_numericality_constraint(*args)
17
17
  reversible do |dir|
18
- dir.up { _add_numericality_constraint(*args) }
18
+ dir.up do _add_numericality_constraint(*args) end
19
19
  dir.down { _remove_numericality_constraint(*args) }
20
20
  end
21
21
  end
22
22
 
23
23
  def remove_numericality_constraint(*args)
24
24
  reversible do |dir|
25
- dir.up { _remove_numericality_constraint(*args) }
25
+ dir.up do _remove_numericality_constraint(*args) end
26
26
  dir.down { _add_numericality_constraint(*args) }
27
27
  end
28
28
  end
@@ -30,17 +30,17 @@ module Rein
30
30
  private
31
31
 
32
32
  def _add_numericality_constraint(table, attribute, options = {})
33
- name = Util.constraint_name(table, attribute, "numericality", options)
34
- conditions = OPERATORS.slice(*options.keys).map do |key, operator|
33
+ name = Util.constraint_name(table, attribute, 'numericality', options)
34
+ conditions = OPERATORS.slice(*options.keys).map { |key, operator|
35
35
  value = options[key]
36
- [attribute, operator, value].join(" ")
37
- end.join(" AND ")
36
+ [attribute, operator, value].join(' ')
37
+ }.join(' AND ')
38
38
  conditions = Util.conditions_with_if(conditions, options)
39
39
  execute("ALTER TABLE #{table} ADD CONSTRAINT #{name} CHECK (#{conditions})")
40
40
  end
41
41
 
42
42
  def _remove_numericality_constraint(table, attribute, options = {})
43
- name = Util.constraint_name(table, attribute, "numericality", options)
43
+ name = Util.constraint_name(table, attribute, 'numericality', options)
44
44
  execute("ALTER TABLE #{table} DROP CONSTRAINT #{name}")
45
45
  end
46
46
  end
@@ -1,4 +1,4 @@
1
- require "rein/util"
1
+ require 'rein/util'
2
2
 
3
3
  module Rein
4
4
  module Constraint
@@ -8,14 +8,14 @@ module Rein
8
8
 
9
9
  def add_presence_constraint(*args)
10
10
  reversible do |dir|
11
- dir.up { _add_presence_constraint(*args) }
11
+ dir.up do _add_presence_constraint(*args) end
12
12
  dir.down { _remove_presence_constraint(*args) }
13
13
  end
14
14
  end
15
15
 
16
16
  def remove_presence_constraint(*args)
17
17
  reversible do |dir|
18
- dir.up { _remove_presence_constraint(*args) }
18
+ dir.up do _remove_presence_constraint(*args) end
19
19
  dir.down { _add_presence_constraint(*args) }
20
20
  end
21
21
  end
@@ -23,7 +23,7 @@ module Rein
23
23
  private
24
24
 
25
25
  def _add_presence_constraint(table, attribute, options = {})
26
- name = Util.constraint_name(table, attribute, "presence", options)
26
+ name = Util.constraint_name(table, attribute, 'presence', options)
27
27
  conditions = Util.conditions_with_if(
28
28
  "(#{attribute} IS NOT NULL) AND (#{attribute} !~ '^\\s*$')",
29
29
  options
@@ -32,7 +32,7 @@ module Rein
32
32
  end
33
33
 
34
34
  def _remove_presence_constraint(table, attribute, options = {})
35
- name = Util.constraint_name(table, attribute, "presence", options)
35
+ name = Util.constraint_name(table, attribute, 'presence', options)
36
36
  execute("ALTER TABLE #{table} DROP CONSTRAINT #{name}")
37
37
  end
38
38
  end
@@ -4,14 +4,14 @@ module Rein
4
4
  module PrimaryKey
5
5
  def add_primary_key(*args)
6
6
  reversible do |dir|
7
- dir.up { _add_primary_key(*args) }
7
+ dir.up do _add_primary_key(*args) end
8
8
  dir.down { _remove_primary_key(*args) }
9
9
  end
10
10
  end
11
11
 
12
12
  def remove_primary_key(*args)
13
13
  reversible do |dir|
14
- dir.up { _remove_primary_key(*args) }
14
+ dir.up do _remove_primary_key(*args) end
15
15
  dir.down { _add_primary_key(*args) }
16
16
  end
17
17
  end
@@ -19,12 +19,12 @@ module Rein
19
19
  private
20
20
 
21
21
  def _add_primary_key(table, options = {})
22
- attribute = (options[:column] || "id").to_sym
22
+ attribute = (options[:column] || 'id').to_sym
23
23
  execute("ALTER TABLE #{table} ADD PRIMARY KEY (#{attribute})")
24
24
  end
25
25
 
26
26
  def _remove_primary_key(table, options = {})
27
- attribute = (options[:column] || "id").to_sym
27
+ attribute = (options[:column] || 'id').to_sym
28
28
  execute("ALTER TABLE #{table} DROP CONSTRAINT #{attribute}_pkey")
29
29
  end
30
30
  end
@@ -0,0 +1,41 @@
1
+ require 'rein/util'
2
+
3
+ module Rein
4
+ module Constraint
5
+ # This module contains methods for defining unique constraints.
6
+ module Unique
7
+ include ActiveRecord::ConnectionAdapters::Quoting
8
+
9
+ def add_unique_constraint(*args)
10
+ reversible do |dir|
11
+ dir.up do _add_unique_constraint(*args) end
12
+ dir.down { _remove_unique_constraint(*args) }
13
+ end
14
+ end
15
+
16
+ def remove_unique_constraint(*args)
17
+ reversible do |dir|
18
+ dir.up do _remove_unique_constraint(*args) end
19
+ dir.down { _add_unique_constraint(*args) }
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def _add_unique_constraint(table, attributes, options = {})
26
+ attributes = [attributes].flatten
27
+ name = Util.constraint_name(table, attributes.join('_'), 'unique', options)
28
+ initially = options[:deferred] ? 'DEFERRED' : 'IMMEDIATE'
29
+ sql = "ALTER TABLE #{table} ADD CONSTRAINT #{name} UNIQUE (#{attributes.join(', ')})"
30
+ sql << " DEFERRABLE INITIALLY #{initially}" unless options[:deferrable] == false
31
+ execute(sql)
32
+ end
33
+
34
+ def _remove_unique_constraint(table, attributes, options = {})
35
+ attributes = [attributes].flatten
36
+ name = Util.constraint_name(table, attributes.join('_'), 'unique', options)
37
+ execute("ALTER TABLE #{table} DROP CONSTRAINT #{name}")
38
+ end
39
+ end
40
+ end
41
+ end
@@ -3,14 +3,14 @@ module Rein
3
3
  module Schema
4
4
  def create_schema(*args)
5
5
  reversible do |dir|
6
- dir.up { _create_schema(*args) }
6
+ dir.up do _create_schema(*args) end
7
7
  dir.down { _drop_schema(*args) }
8
8
  end
9
9
  end
10
10
 
11
11
  def drop_schema(*args)
12
12
  reversible do |dir|
13
- dir.up { _drop_schema(*args) }
13
+ dir.up do _drop_schema(*args) end
14
14
  dir.down { _create_schema(*args) }
15
15
  end
16
16
  end
@@ -1,4 +1,4 @@
1
- require "active_record/connection_adapters/abstract/quoting"
1
+ require 'active_record/connection_adapters/abstract/quoting'
2
2
 
3
3
  module Rein
4
4
  module Type
@@ -8,14 +8,14 @@ module Rein
8
8
 
9
9
  def create_enum_type(*args)
10
10
  reversible do |dir|
11
- dir.up { _create_enum_type(*args) }
11
+ dir.up do _create_enum_type(*args) end
12
12
  dir.down { _drop_enum_type(*args) }
13
13
  end
14
14
  end
15
15
 
16
16
  def drop_enum_type(*args)
17
17
  reversible do |dir|
18
- dir.up { _drop_enum_type(*args) }
18
+ dir.up do _drop_enum_type(*args) end
19
19
  dir.down { _create_enum_type(*args) }
20
20
  end
21
21
  end
@@ -27,7 +27,7 @@ module Rein
27
27
  private
28
28
 
29
29
  def _create_enum_type(enum_name, enum_values = [])
30
- enum_values = enum_values.map { |value| quote(value) }.join(", ")
30
+ enum_values = enum_values.map { |value| quote(value) }.join(', ')
31
31
  execute("CREATE TYPE #{enum_name} AS ENUM (#{enum_values})")
32
32
  end
33
33
 
@@ -1,3 +1,3 @@
1
1
  module Rein
2
- VERSION = "3.2.0".freeze
2
+ VERSION = '3.3.0'.freeze
3
3
  end
@@ -3,14 +3,14 @@ module Rein
3
3
  module View
4
4
  def create_view(*args)
5
5
  reversible do |dir|
6
- dir.up { _create_view(*args) }
6
+ dir.up do _create_view(*args) end
7
7
  dir.down { _drop_view(*args) }
8
8
  end
9
9
  end
10
10
 
11
11
  def drop_view(*args)
12
12
  reversible do |dir|
13
- dir.up { _drop_view(*args) }
13
+ dir.up do _drop_view(*args) end
14
14
  dir.down { _create_view(*args) }
15
15
  end
16
16
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rein
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Bassett
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-28 00:00:00.000000000 Z
11
+ date: 2017-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -56,56 +56,56 @@ dependencies:
56
56
  requirements:
57
57
  - - "~>"
58
58
  - !ruby/object:Gem::Version
59
- version: '2.1'
59
+ version: '2.2'
60
60
  type: :development
61
61
  prerelease: false
62
62
  version_requirements: !ruby/object:Gem::Requirement
63
63
  requirements:
64
64
  - - "~>"
65
65
  - !ruby/object:Gem::Version
66
- version: '2.1'
66
+ version: '2.2'
67
67
  - !ruby/object:Gem::Dependency
68
68
  name: bundler
69
69
  requirement: !ruby/object:Gem::Requirement
70
70
  requirements:
71
71
  - - "~>"
72
72
  - !ruby/object:Gem::Version
73
- version: '1.14'
73
+ version: '1.16'
74
74
  type: :development
75
75
  prerelease: false
76
76
  version_requirements: !ruby/object:Gem::Requirement
77
77
  requirements:
78
78
  - - "~>"
79
79
  - !ruby/object:Gem::Version
80
- version: '1.14'
80
+ version: '1.16'
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: pg
83
83
  requirement: !ruby/object:Gem::Requirement
84
84
  requirements:
85
85
  - - "~>"
86
86
  - !ruby/object:Gem::Version
87
- version: '0.20'
87
+ version: '0.21'
88
88
  type: :development
89
89
  prerelease: false
90
90
  version_requirements: !ruby/object:Gem::Requirement
91
91
  requirements:
92
92
  - - "~>"
93
93
  - !ruby/object:Gem::Version
94
- version: '0.20'
94
+ version: '0.21'
95
95
  - !ruby/object:Gem::Dependency
96
96
  name: rake
97
97
  requirement: !ruby/object:Gem::Requirement
98
98
  requirements:
99
99
  - - "~>"
100
100
  - !ruby/object:Gem::Version
101
- version: '12.0'
101
+ version: '12.3'
102
102
  type: :development
103
103
  prerelease: false
104
104
  version_requirements: !ruby/object:Gem::Requirement
105
105
  requirements:
106
106
  - - "~>"
107
107
  - !ruby/object:Gem::Version
108
- version: '12.0'
108
+ version: '12.3'
109
109
  - !ruby/object:Gem::Dependency
110
110
  name: rspec
111
111
  requirement: !ruby/object:Gem::Requirement
@@ -153,6 +153,7 @@ files:
153
153
  - lib/rein/constraint/numericality.rb
154
154
  - lib/rein/constraint/presence.rb
155
155
  - lib/rein/constraint/primary_key.rb
156
+ - lib/rein/constraint/unique.rb
156
157
  - lib/rein/schema.rb
157
158
  - lib/rein/type/enum.rb
158
159
  - lib/rein/util.rb