nandi 0.8.0 → 0.11.1

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
  SHA256:
3
- metadata.gz: e9c08faeee8155ae5b0e5357cabca63c2f31bfd65fb464e16991b47c4b9cab75
4
- data.tar.gz: 0e408aa01adaf0ce11560acef08d899c208d2c4e3afdd31b3fb9777a0d0b2408
3
+ metadata.gz: 6e1e64259650cb225c127f8a89c899464864a9d5ca76fb4abd58d48c6930e624
4
+ data.tar.gz: 41ef391e7da05c3997a13adf87ff5aa032fd6a46762d4cc7263c691d179ed237
5
5
  SHA512:
6
- metadata.gz: fe9b90ee4085d5f7d208e481f9ae4fca325f87ab37ff7b3c1a74063adbe65a7777ab66e8afbb8b4d18408362ef1c71f88884eeab6643c19ffd3e8de3f98b007f
7
- data.tar.gz: fdbca6280d8c5299661b78fa1163593f903605c056337c3e55b3ca512370717fa7c8af97bfe055393205a6c15fe224aa32a97616dfec8fb118daf39a10b42ca0
6
+ metadata.gz: 1672112e9464d5f8cefd75477cd7cdbae2d05822b0544d9f9240140b55121171e8f7e4183b09a5fcb2ab0d240e701aa891faebb5e99bafd5e4e764e2079e4f9d
7
+ data.tar.gz: 490135828100e636745efc67dfece39f04506ce18b135ab7487041b0929302b59973ae2848b7eef899dbd347050767c0f20fb3e1bdca73d0228d4e19c84e1279
data/README.md CHANGED
@@ -4,7 +4,7 @@ Friendly Postgres migrations for people who don't want to take down their databa
4
4
 
5
5
  ## Supported
6
6
 
7
- - Ruby 2.4 or above
7
+ - Ruby 2.5 or above
8
8
  - Rails 5.2 or above
9
9
  - Postgres 11 or above
10
10
 
@@ -161,11 +161,11 @@ We now have three new migration files:
161
161
 
162
162
  class AddReferenceOnFoosToBars < Nandi::Migration
163
163
  def up
164
- add_reference :foos, :bar
164
+ add_column :foos, :bar_id, :bigint
165
165
  end
166
166
 
167
167
  def down
168
- remove_reference :foos, :bar
168
+ remove_column :foos, :bar_id
169
169
  end
170
170
  end
171
171
 
@@ -202,10 +202,10 @@ class AddReferenceOnFoosToBars < ActiveRecord::Migration[5.2]
202
202
  set_statement_timeout(1_500)
203
203
 
204
204
  def up
205
- add_reference(:foos, :bar)
205
+ add_column(:foos, :bar_id, :bigint)
206
206
  end
207
207
  def down
208
- remove_reference(:foos, :bar)
208
+ remove_column(:foos, :bar_id)
209
209
  end
210
210
  end
211
211
 
@@ -268,10 +268,9 @@ Add a foreign key constraint. The generated SQL will include the NOT VALID param
268
268
  ### `#add_index(table, fields, **kwargs)`
269
269
  Adds a new index to the database.
270
270
 
271
- Nandi will:
272
-
271
+ Nandi will
273
272
  - add the `CONCURRENTLY` option, which means the change takes a less restrictive lock at the cost of not running in a DDL transaction
274
- - use the `BTREE` index type which is the safest to create.
273
+ - default to the `BTREE` index type, as it is commonly a good fit.
275
274
 
276
275
  Because index creation is particularly failure-prone, and because we cannot run in a transaction and therefore risk partially applied migrations that (in a Rails environment) require manual intervention, Nandi Validates that, if there is a add_index statement in the migration, it must be the only statement.
277
276
 
@@ -287,7 +286,7 @@ end
287
286
  ```
288
287
 
289
288
  ### `#add_reference(table, ref_name, **extra_args)`
290
- Adds a new reference column. Nandi will validate that the foreign key flag is not set to true; use `add_foreign_key` and `validate_foreign_key` instead!
289
+ Adds a new reference column. Nandi will validate that the foreign key flag is not set to true; use `add_foreign_key` and `validate_foreign_key` instead! Nandi will also set the `index: false` flag, as index creation is unsafe unless done concurrently in a separate migration.
291
290
 
292
291
  ### `#remove_reference(table, ref_name, **extra_args)`
293
292
  Removes a reference column.
data/exe/nandi-enforce CHANGED
@@ -31,6 +31,6 @@ OptionParser.new do |o|
31
31
  end
32
32
  end.parse!
33
33
 
34
- enforcer = Nandi::SafeMigrationEnforcer.new(opts)
34
+ enforcer = Nandi::SafeMigrationEnforcer.new(**opts)
35
35
 
36
36
  enforcer.run
@@ -11,7 +11,7 @@ module Nandi
11
11
  argument :target, type: :string
12
12
  class_option :name, type: :string
13
13
  class_option :column, type: :string
14
- class_option :type, type: :string
14
+ class_option :type, type: :string, default: "bigint"
15
15
  class_option :no_create_column, type: :boolean
16
16
  class_option :validation_timeout, type: :numeric, default: 15 * 60 * 1000
17
17
 
@@ -61,11 +61,11 @@ module Nandi
61
61
  private
62
62
 
63
63
  def type
64
- options["type"]&.to_sym
64
+ options["type"].to_sym
65
65
  end
66
66
 
67
67
  def reference_name
68
- target.singularize.to_sym
68
+ "#{target.singularize}_id".to_sym
69
69
  end
70
70
 
71
71
  def base_path
@@ -2,10 +2,10 @@
2
2
 
3
3
  class <%= add_reference_name.camelize %> < Nandi::Migration
4
4
  def up
5
- add_reference <%= format_value(table) %>, <%= format_value(reference_name) %><% if type %>, type: <%= format_value(type) %><% end %>
5
+ add_column <%= format_value(table) %>, <%= format_value(reference_name) %>, <%= format_value(type) %>
6
6
  end
7
7
 
8
8
  def down
9
- remove_reference <%= format_value(table) %>, <%= format_value(reference_name) %>
9
+ remove_column <%= format_value(table) %>, <%= format_value(reference_name) %>
10
10
  end
11
11
  end
@@ -64,7 +64,7 @@ module Nandi
64
64
  key = if k.is_a?(Symbol)
65
65
  symbol_key(k)
66
66
  else
67
- format_value(k) + " =>"
67
+ "#{format_value(k)} =>"
68
68
  end
69
69
  "#{key} #{format_value(v)}"
70
70
  end
@@ -21,11 +21,10 @@ module Nandi
21
21
  name: name,
22
22
 
23
23
  # Overrides and extra options
24
- **@extra_args,
24
+ **extra_args_with_default_index_type,
25
25
 
26
26
  # Mandatory values
27
27
  algorithm: :concurrently,
28
- using: :btree,
29
28
  }
30
29
  end
31
30
 
@@ -38,13 +37,19 @@ module Nandi
38
37
  private
39
38
 
40
39
  def name
41
- :"idx_#{table.to_s}_on_#{field_names}"
40
+ :"idx_#{table}_on_#{field_names}"
42
41
  end
43
42
 
44
43
  def field_names
45
44
  field_names = fields.respond_to?(:map) ? fields.map(&:to_s).join("_") : fields
46
45
  field_names.to_s.scan(/\w+/).join("_")
47
46
  end
47
+
48
+ def extra_args_with_default_index_type
49
+ {
50
+ using: :btree,
51
+ }.merge(@extra_args)
52
+ end
48
53
  end
49
54
  end
50
55
  end
@@ -3,12 +3,13 @@
3
3
  module Nandi
4
4
  module Instructions
5
5
  class AddReference
6
+ DEFAULT_EXTRA_ARGS = { index: false }.freeze
6
7
  attr_reader :table, :ref_name, :extra_args
7
8
 
8
9
  def initialize(table:, ref_name:, **kwargs)
9
10
  @table = table
10
11
  @ref_name = ref_name
11
- @extra_args = kwargs
12
+ @extra_args = DEFAULT_EXTRA_ARGS.merge(kwargs)
12
13
  end
13
14
 
14
15
  def procedure
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/hash/indifferent_access"
4
+ require "digest"
4
5
 
5
6
  module Nandi
6
7
  class Lockfile
@@ -42,7 +43,26 @@ module Nandi
42
43
  end
43
44
 
44
45
  def persist!
45
- File.write(path, lockfile.to_h.deep_stringify_keys.to_yaml)
46
+ # This is a somewhat ridiculous trick to avoid merge conflicts in git.
47
+ #
48
+ # Normally, new migrations are added to the bottom of the Nandi lockfile.
49
+ # This is relatively unfriendly to git's merge algorithm, and means that
50
+ # if someone merges a pull request with a completely unrelated migration,
51
+ # you'll have to rebase to get yours merged as the last line of the file
52
+ # will be seen as a conflict (both branches added content there).
53
+ #
54
+ # This is in contrast to something like Gemfile.lock, where changes tend
55
+ # to be distributed throughout the file. The idea behind sorting by
56
+ # SHA-256 hash is to distribute new Nandi lockfile entries evenly, but
57
+ # also stably through the file. It needs to be stable or we'd have even
58
+ # worse merge conflict problems (e.g. if we randomised the order on
59
+ # writing the file, the whole thing would conflict pretty much every time
60
+ # it was regenerated).
61
+ content = Hash[lockfile.to_h.deep_stringify_keys.sort_by do |k, _|
62
+ Digest::SHA256.hexdigest(k)
63
+ end].to_yaml
64
+
65
+ File.write(path, content)
46
66
  end
47
67
 
48
68
  def path
@@ -43,6 +43,7 @@ module Nandi
43
43
 
44
44
  class << self
45
45
  attr_reader :lock_timeout, :statement_timeout
46
+
46
47
  # For sake both of correspondence with Postgres syntax and familiarity
47
48
  # with activerecord-safe_migrations's identically named macros, we
48
49
  # disable this cop.
@@ -111,7 +112,7 @@ module Nandi
111
112
  # Nandi will:
112
113
  # * add the `CONCURRENTLY` option, which means the change takes a less
113
114
  # restrictive lock at the cost of not running in a DDL transaction
114
- # * use the `BTREE` index type which is the safest to create.
115
+ # * default to the `BTREE` index type, as it is commonly a good fit.
115
116
  #
116
117
  # Because index creation is particularly failure-prone, and because
117
118
  # we cannot run in a transaction and therefore risk partially applied
@@ -16,16 +16,28 @@ module Nandi
16
16
  end
17
17
 
18
18
  def call
19
- foreign_key = instruction.extra_args.fetch(:foreign_key) { false }
20
-
21
- assert(
22
- !foreign_key,
23
- foreign_key_message,
19
+ foreign_key = instruction.extra_args.fetch(:foreign_key, false)
20
+ index = instruction.extra_args.fetch(:index, false)
21
+
22
+ collect_errors(
23
+ assert(
24
+ !foreign_key,
25
+ foreign_key_message,
26
+ ),
27
+ assert(
28
+ !index,
29
+ index_message,
30
+ ),
24
31
  )
25
32
  end
26
33
 
27
34
  private
28
35
 
36
+ def index_message
37
+ "Indexing a reference column on creation can make the table unavailable." \
38
+ "Use the `add_index` method in a separate migration to index the column."
39
+ end
40
+
29
41
  def foreign_key_message
30
42
  "Adding a foreign key constraint must be done in two separate migrations. " \
31
43
  "Use the `add_foreign_key` and `validate_foreign_key` methods, or the " \
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nandi
4
+ VERSION = "0.11.1"
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nandi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.11.1
5
5
  platform: ruby
6
6
  authors:
7
- - James Turley
8
- autorequire:
7
+ - GoCardless Engineering
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-04 00:00:00.000000000 Z
11
+ date: 2021-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -100,28 +100,28 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 2.3.14
103
+ version: 2.15.0
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 2.3.14
110
+ version: 2.15.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: pry-byebug
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 3.7.0
117
+ version: 3.9.0
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 3.7.0
124
+ version: 3.9.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rails
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -140,16 +140,22 @@ dependencies:
140
140
  name: rake
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: 12.3.3
143
146
  - - "~>"
144
147
  - !ruby/object:Gem::Version
145
- version: '10.0'
148
+ version: '13.0'
146
149
  type: :development
147
150
  prerelease: false
148
151
  version_requirements: !ruby/object:Gem::Requirement
149
152
  requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: 12.3.3
150
156
  - - "~>"
151
157
  - !ruby/object:Gem::Version
152
- version: '10.0'
158
+ version: '13.0'
153
159
  - !ruby/object:Gem::Dependency
154
160
  name: rspec
155
161
  requirement: !ruby/object:Gem::Requirement
@@ -184,14 +190,14 @@ dependencies:
184
190
  requirements:
185
191
  - - "~>"
186
192
  - !ruby/object:Gem::Version
187
- version: '0.61'
193
+ version: '1.0'
188
194
  type: :development
189
195
  prerelease: false
190
196
  version_requirements: !ruby/object:Gem::Requirement
191
197
  requirements:
192
198
  - - "~>"
193
199
  - !ruby/object:Gem::Version
194
- version: '0.61'
200
+ version: '1.0'
195
201
  - !ruby/object:Gem::Dependency
196
202
  name: yard
197
203
  requirement: !ruby/object:Gem::Requirement
@@ -206,9 +212,9 @@ dependencies:
206
212
  - - "~>"
207
213
  - !ruby/object:Gem::Version
208
214
  version: '0.9'
209
- description:
215
+ description:
210
216
  email:
211
- - jamesturley@gocardless.com
217
+ - engineering@gocardless.com
212
218
  executables:
213
219
  - nandi-enforce
214
220
  extensions: []
@@ -276,6 +282,7 @@ files:
276
282
  - lib/nandi/validation/result.rb
277
283
  - lib/nandi/validation/timeout_validator.rb
278
284
  - lib/nandi/validator.rb
285
+ - lib/nandi/version.rb
279
286
  - lib/templates/nandi/renderers/active_record/generate/show.rb.erb
280
287
  - lib/templates/nandi/renderers/active_record/instructions/add_check_constraint/show.rb.erb
281
288
  - lib/templates/nandi/renderers/active_record/instructions/add_column/show.rb.erb
@@ -292,10 +299,11 @@ files:
292
299
  - lib/templates/nandi/renderers/active_record/instructions/remove_not_null_constraint/show.rb.erb
293
300
  - lib/templates/nandi/renderers/active_record/instructions/remove_reference/show.rb.erb
294
301
  - lib/templates/nandi/renderers/active_record/instructions/validate_constraint/show.rb.erb
295
- homepage:
296
- licenses: []
302
+ homepage: https://github.com/gocardless/nandi
303
+ licenses:
304
+ - MIT
297
305
  metadata: {}
298
- post_install_message:
306
+ post_install_message:
299
307
  rdoc_options: []
300
308
  require_paths:
301
309
  - lib
@@ -303,15 +311,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
303
311
  requirements:
304
312
  - - ">="
305
313
  - !ruby/object:Gem::Version
306
- version: '0'
314
+ version: 2.4.0
307
315
  required_rubygems_version: !ruby/object:Gem::Requirement
308
316
  requirements:
309
317
  - - ">="
310
318
  - !ruby/object:Gem::Version
311
319
  version: '0'
312
320
  requirements: []
313
- rubygems_version: 3.0.3
314
- signing_key:
321
+ rubygems_version: 3.2.3
322
+ signing_key:
315
323
  specification_version: 4
316
324
  summary: Fear-free migrations for PostgreSQL
317
325
  test_files: []