rein 3.2.0 → 3.3.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.
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