nandi 0.9.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 +7 -0
- data/README.md +477 -0
- data/Rakefile +8 -0
- data/exe/nandi-enforce +36 -0
- data/lib/generators/nandi/check_constraint/USAGE +19 -0
- data/lib/generators/nandi/check_constraint/check_constraint_generator.rb +52 -0
- data/lib/generators/nandi/check_constraint/templates/add_check_constraint.rb +15 -0
- data/lib/generators/nandi/check_constraint/templates/validate_check_constraint.rb +9 -0
- data/lib/generators/nandi/compile/USAGE +19 -0
- data/lib/generators/nandi/compile/compile_generator.rb +62 -0
- data/lib/generators/nandi/foreign_key/USAGE +47 -0
- data/lib/generators/nandi/foreign_key/foreign_key_generator.rb +91 -0
- data/lib/generators/nandi/foreign_key/templates/add_foreign_key.rb +13 -0
- data/lib/generators/nandi/foreign_key/templates/add_reference.rb +11 -0
- data/lib/generators/nandi/foreign_key/templates/validate_foreign_key.rb +9 -0
- data/lib/generators/nandi/migration/USAGE +9 -0
- data/lib/generators/nandi/migration/migration_generator.rb +24 -0
- data/lib/generators/nandi/migration/templates/migration.rb +13 -0
- data/lib/generators/nandi/not_null_check/USAGE +19 -0
- data/lib/generators/nandi/not_null_check/not_null_check_generator.rb +56 -0
- data/lib/generators/nandi/not_null_check/templates/add_not_null_check.rb +11 -0
- data/lib/generators/nandi/not_null_check/templates/validate_not_null_check.rb +9 -0
- data/lib/nandi.rb +35 -0
- data/lib/nandi/compiled_migration.rb +86 -0
- data/lib/nandi/config.rb +126 -0
- data/lib/nandi/file_diff.rb +32 -0
- data/lib/nandi/file_matcher.rb +72 -0
- data/lib/nandi/formatting.rb +79 -0
- data/lib/nandi/instructions.rb +19 -0
- data/lib/nandi/instructions/add_check_constraint.rb +23 -0
- data/lib/nandi/instructions/add_column.rb +24 -0
- data/lib/nandi/instructions/add_foreign_key.rb +40 -0
- data/lib/nandi/instructions/add_index.rb +50 -0
- data/lib/nandi/instructions/change_column_default.rb +23 -0
- data/lib/nandi/instructions/create_table.rb +83 -0
- data/lib/nandi/instructions/drop_constraint.rb +22 -0
- data/lib/nandi/instructions/drop_table.rb +21 -0
- data/lib/nandi/instructions/irreversible_migration.rb +15 -0
- data/lib/nandi/instructions/remove_column.rb +23 -0
- data/lib/nandi/instructions/remove_index.rb +41 -0
- data/lib/nandi/instructions/remove_not_null_constraint.rb +22 -0
- data/lib/nandi/instructions/validate_constraint.rb +22 -0
- data/lib/nandi/lockfile.rb +58 -0
- data/lib/nandi/migration.rb +363 -0
- data/lib/nandi/renderers.rb +7 -0
- data/lib/nandi/renderers/active_record.rb +13 -0
- data/lib/nandi/renderers/active_record/generate.rb +59 -0
- data/lib/nandi/renderers/active_record/instructions.rb +134 -0
- data/lib/nandi/safe_migration_enforcer.rb +143 -0
- data/lib/nandi/timeout_policies.rb +38 -0
- data/lib/nandi/timeout_policies/access_exclusive.rb +54 -0
- data/lib/nandi/timeout_policies/concurrent.rb +64 -0
- data/lib/nandi/validation.rb +10 -0
- data/lib/nandi/validation/add_column_validator.rb +43 -0
- data/lib/nandi/validation/each_validator.rb +32 -0
- data/lib/nandi/validation/failure_helpers.rb +35 -0
- data/lib/nandi/validation/remove_index_validator.rb +30 -0
- data/lib/nandi/validation/result.rb +30 -0
- data/lib/nandi/validation/timeout_validator.rb +37 -0
- data/lib/nandi/validator.rb +102 -0
- data/lib/nandi/version.rb +5 -0
- data/lib/templates/nandi/renderers/active_record/generate/show.rb.erb +27 -0
- data/lib/templates/nandi/renderers/active_record/instructions/add_check_constraint/show.rb.erb +7 -0
- data/lib/templates/nandi/renderers/active_record/instructions/add_column/show.rb.erb +6 -0
- data/lib/templates/nandi/renderers/active_record/instructions/add_foreign_key/show.rb.erb +5 -0
- data/lib/templates/nandi/renderers/active_record/instructions/add_index/show.rb.erb +5 -0
- data/lib/templates/nandi/renderers/active_record/instructions/change_column_default/show.rb.erb +1 -0
- data/lib/templates/nandi/renderers/active_record/instructions/create_table/show.rb.erb +8 -0
- data/lib/templates/nandi/renderers/active_record/instructions/drop_constraint/show.rb.erb +4 -0
- data/lib/templates/nandi/renderers/active_record/instructions/drop_table/show.rb.erb +1 -0
- data/lib/templates/nandi/renderers/active_record/instructions/irreversible_migration/show.rb.erb +1 -0
- data/lib/templates/nandi/renderers/active_record/instructions/remove_column/show.rb.erb +5 -0
- data/lib/templates/nandi/renderers/active_record/instructions/remove_index/show.rb.erb +4 -0
- data/lib/templates/nandi/renderers/active_record/instructions/remove_not_null_constraint/show.rb.erb +1 -0
- data/lib/templates/nandi/renderers/active_record/instructions/validate_constraint/show.rb.erb +3 -0
- metadata +320 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nandi
|
4
|
+
module Formatting
|
5
|
+
class UnsupportedValueError < StandardError; end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
# Define an accessor method that will retrieve a value
|
9
|
+
# from a cell's model and format it with the format_value
|
10
|
+
# method below.
|
11
|
+
# @param name [String] the attribute on model to retrieve
|
12
|
+
# @example formatting the foo property
|
13
|
+
# class MyCell < Cells::ViewModel
|
14
|
+
# include Nandi::Formatting
|
15
|
+
#
|
16
|
+
# formatted_property :foo
|
17
|
+
# end
|
18
|
+
def formatted_property(name)
|
19
|
+
define_method(name) do
|
20
|
+
format_value(model.send(name))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Create a string representation of the value that is a valid
|
26
|
+
# and correct Ruby literal for that value. Please note that the
|
27
|
+
# exact representation is not guaranteed to be the same between
|
28
|
+
# different platforms and Ruby versions. The guarantee is merely
|
29
|
+
# that calling this method with any supported type will produce
|
30
|
+
# a string that produces an equal value when it is passed to
|
31
|
+
# Kernel::eval
|
32
|
+
# @param value [Hash, Array, String, Symbol, Integer, Float, NilClass]
|
33
|
+
# value to format
|
34
|
+
def format_value(value, opts = {})
|
35
|
+
case value
|
36
|
+
when Hash
|
37
|
+
format_hash(value, opts)
|
38
|
+
when Array
|
39
|
+
"[#{value.map { |v| format_value(v, opts) }.join(', ')}]"
|
40
|
+
when String, Symbol, Integer, Float, NilClass, TrueClass, FalseClass
|
41
|
+
value.inspect
|
42
|
+
else
|
43
|
+
raise UnsupportedValueError,
|
44
|
+
"Cannot format value of type #{value.class.name}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.included(base)
|
49
|
+
base.extend(ClassMethods)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def format_hash(value, opts)
|
55
|
+
if opts[:as_argument]
|
56
|
+
hash_pairs(value).join(", ")
|
57
|
+
else
|
58
|
+
"{\n #{hash_pairs(value).join(",\n ")}\n}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def hash_pairs(value)
|
63
|
+
value.map do |k, v|
|
64
|
+
key = if k.is_a?(Symbol)
|
65
|
+
symbol_key(k)
|
66
|
+
else
|
67
|
+
format_value(k) + " =>"
|
68
|
+
end
|
69
|
+
"#{key} #{format_value(v)}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def symbol_key(key)
|
74
|
+
canonical = key.inspect
|
75
|
+
|
76
|
+
"#{canonical[1..-1]}:"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "nandi/instructions/add_index"
|
4
|
+
require "nandi/instructions/remove_index"
|
5
|
+
require "nandi/instructions/create_table"
|
6
|
+
require "nandi/instructions/drop_table"
|
7
|
+
require "nandi/instructions/add_column"
|
8
|
+
require "nandi/instructions/remove_column"
|
9
|
+
require "nandi/instructions/add_foreign_key"
|
10
|
+
require "nandi/instructions/drop_constraint"
|
11
|
+
require "nandi/instructions/remove_not_null_constraint"
|
12
|
+
require "nandi/instructions/change_column_default"
|
13
|
+
require "nandi/instructions/validate_constraint"
|
14
|
+
require "nandi/instructions/add_check_constraint"
|
15
|
+
require "nandi/instructions/irreversible_migration"
|
16
|
+
|
17
|
+
module Nandi
|
18
|
+
module Instructions; end
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nandi
|
4
|
+
module Instructions
|
5
|
+
class AddCheckConstraint
|
6
|
+
attr_reader :table, :name, :check
|
7
|
+
|
8
|
+
def initialize(table:, name:, check:)
|
9
|
+
@table = table
|
10
|
+
@name = name
|
11
|
+
@check = check
|
12
|
+
end
|
13
|
+
|
14
|
+
def procedure
|
15
|
+
:add_check_constraint
|
16
|
+
end
|
17
|
+
|
18
|
+
def lock
|
19
|
+
Nandi::Migration::LockWeights::ACCESS_EXCLUSIVE
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nandi
|
4
|
+
module Instructions
|
5
|
+
class AddColumn
|
6
|
+
attr_reader :table, :name, :type, :extra_args
|
7
|
+
|
8
|
+
def initialize(table:, name:, type:, **kwargs)
|
9
|
+
@table = table
|
10
|
+
@name = name
|
11
|
+
@type = type
|
12
|
+
@extra_args = kwargs
|
13
|
+
end
|
14
|
+
|
15
|
+
def procedure
|
16
|
+
:add_column
|
17
|
+
end
|
18
|
+
|
19
|
+
def lock
|
20
|
+
Nandi::Migration::LockWeights::ACCESS_EXCLUSIVE
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/inflector"
|
4
|
+
|
5
|
+
module Nandi
|
6
|
+
module Instructions
|
7
|
+
class AddForeignKey
|
8
|
+
attr_reader :table, :target
|
9
|
+
|
10
|
+
def initialize(table:, target:, name: nil, **extra_args)
|
11
|
+
@table = table
|
12
|
+
@target = target
|
13
|
+
@extra_args = extra_args
|
14
|
+
@name = name
|
15
|
+
end
|
16
|
+
|
17
|
+
def procedure
|
18
|
+
:add_foreign_key
|
19
|
+
end
|
20
|
+
|
21
|
+
def extra_args
|
22
|
+
{
|
23
|
+
**@extra_args,
|
24
|
+
name: name,
|
25
|
+
validate: false,
|
26
|
+
}.compact
|
27
|
+
end
|
28
|
+
|
29
|
+
def lock
|
30
|
+
Nandi::Migration::LockWeights::ACCESS_EXCLUSIVE
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def name
|
36
|
+
@name || :"#{table}_#{target}_fk"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nandi
|
4
|
+
module Instructions
|
5
|
+
class AddIndex
|
6
|
+
def initialize(fields:, table:, **kwargs)
|
7
|
+
@fields = Array(fields)
|
8
|
+
@fields = @fields.first if @fields.one?
|
9
|
+
|
10
|
+
@table = table
|
11
|
+
@extra_args = kwargs
|
12
|
+
end
|
13
|
+
|
14
|
+
def procedure
|
15
|
+
:add_index
|
16
|
+
end
|
17
|
+
|
18
|
+
def extra_args
|
19
|
+
{
|
20
|
+
# Overridable defaults
|
21
|
+
name: name,
|
22
|
+
|
23
|
+
# Overrides and extra options
|
24
|
+
**@extra_args,
|
25
|
+
|
26
|
+
# Mandatory values
|
27
|
+
algorithm: :concurrently,
|
28
|
+
using: :btree,
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def lock
|
33
|
+
Nandi::Migration::LockWeights::SHARE
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :table, :fields
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def name
|
41
|
+
:"idx_#{table.to_s}_on_#{field_names}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def field_names
|
45
|
+
field_names = fields.respond_to?(:map) ? fields.map(&:to_s).join("_") : fields
|
46
|
+
field_names.to_s.scan(/\w+/).join("_")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nandi
|
4
|
+
module Instructions
|
5
|
+
class ChangeColumnDefault
|
6
|
+
attr_reader :table, :column, :value
|
7
|
+
|
8
|
+
def initialize(table:, column:, value:)
|
9
|
+
@table = table
|
10
|
+
@column = column
|
11
|
+
@value = value
|
12
|
+
end
|
13
|
+
|
14
|
+
def procedure
|
15
|
+
:change_column_default
|
16
|
+
end
|
17
|
+
|
18
|
+
def lock
|
19
|
+
Nandi::Migration::LockWeights::ACCESS_EXCLUSIVE
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ostruct"
|
4
|
+
|
5
|
+
module Nandi
|
6
|
+
module Instructions
|
7
|
+
class CreateTable
|
8
|
+
attr_reader :table, :columns, :timestamps_args, :extra_args
|
9
|
+
|
10
|
+
def initialize(table:, columns_block:, **kwargs)
|
11
|
+
@table = table
|
12
|
+
columns_reader = ColumnsReader.new
|
13
|
+
columns_block.call(columns_reader)
|
14
|
+
@columns = columns_reader.columns
|
15
|
+
@extra_args = kwargs unless kwargs.empty?
|
16
|
+
@timestamps_args = columns_reader.timestamps_args
|
17
|
+
end
|
18
|
+
|
19
|
+
def procedure
|
20
|
+
:create_table
|
21
|
+
end
|
22
|
+
|
23
|
+
def lock
|
24
|
+
Nandi::Migration::LockWeights::ACCESS_EXCLUSIVE
|
25
|
+
end
|
26
|
+
|
27
|
+
class ColumnsReader
|
28
|
+
attr_reader :columns, :timestamps_args
|
29
|
+
|
30
|
+
TYPES = %i[
|
31
|
+
bigint
|
32
|
+
binary
|
33
|
+
boolean
|
34
|
+
date
|
35
|
+
datetime
|
36
|
+
decimal
|
37
|
+
float
|
38
|
+
integer
|
39
|
+
json
|
40
|
+
string
|
41
|
+
text
|
42
|
+
time
|
43
|
+
timestamp
|
44
|
+
virtual
|
45
|
+
bigserial bit bit_varying box
|
46
|
+
cidr circle citext
|
47
|
+
daterange
|
48
|
+
hstore
|
49
|
+
inet int4range int8range interval
|
50
|
+
jsonb
|
51
|
+
line lseg ltree
|
52
|
+
macaddr money
|
53
|
+
numrange
|
54
|
+
oid
|
55
|
+
path point polygon primary_key
|
56
|
+
serial
|
57
|
+
tsrange tstzrange tsvector
|
58
|
+
uuid
|
59
|
+
xml
|
60
|
+
].freeze
|
61
|
+
|
62
|
+
def initialize
|
63
|
+
@columns = []
|
64
|
+
@timestamps_args = nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def column(name, type, **args)
|
68
|
+
@columns << OpenStruct.new(name: name, type: type, args: args)
|
69
|
+
end
|
70
|
+
|
71
|
+
def timestamps(**args)
|
72
|
+
@timestamps_args = args
|
73
|
+
end
|
74
|
+
|
75
|
+
TYPES.each do |type|
|
76
|
+
define_method type do |name, **args|
|
77
|
+
column(name, type, **args)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nandi
|
4
|
+
module Instructions
|
5
|
+
class DropConstraint
|
6
|
+
attr_reader :table, :name
|
7
|
+
|
8
|
+
def initialize(table:, name:)
|
9
|
+
@table = table
|
10
|
+
@name = name
|
11
|
+
end
|
12
|
+
|
13
|
+
def procedure
|
14
|
+
:drop_constraint
|
15
|
+
end
|
16
|
+
|
17
|
+
def lock
|
18
|
+
Nandi::Migration::LockWeights::ACCESS_EXCLUSIVE
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nandi
|
4
|
+
module Instructions
|
5
|
+
class DropTable
|
6
|
+
attr_reader :table
|
7
|
+
|
8
|
+
def initialize(table:)
|
9
|
+
@table = table
|
10
|
+
end
|
11
|
+
|
12
|
+
def procedure
|
13
|
+
:drop_table
|
14
|
+
end
|
15
|
+
|
16
|
+
def lock
|
17
|
+
Nandi::Migration::LockWeights::ACCESS_EXCLUSIVE
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nandi
|
4
|
+
module Instructions
|
5
|
+
class RemoveColumn
|
6
|
+
attr_reader :table, :name, :extra_args
|
7
|
+
|
8
|
+
def initialize(table:, name:, **extra_args)
|
9
|
+
@table = table
|
10
|
+
@name = name
|
11
|
+
@extra_args = extra_args if extra_args.any?
|
12
|
+
end
|
13
|
+
|
14
|
+
def procedure
|
15
|
+
:remove_column
|
16
|
+
end
|
17
|
+
|
18
|
+
def lock
|
19
|
+
Nandi::Migration::LockWeights::ACCESS_EXCLUSIVE
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nandi
|
4
|
+
module Instructions
|
5
|
+
class RemoveIndex
|
6
|
+
def initialize(table:, field:)
|
7
|
+
@table = table
|
8
|
+
@field = field
|
9
|
+
end
|
10
|
+
|
11
|
+
def procedure
|
12
|
+
:remove_index
|
13
|
+
end
|
14
|
+
|
15
|
+
def extra_args
|
16
|
+
if field.is_a?(Hash)
|
17
|
+
field.merge(algorithm: :concurrently)
|
18
|
+
else
|
19
|
+
{ column: columns, algorithm: :concurrently }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def lock
|
24
|
+
Nandi::Migration::LockWeights::SHARE
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_reader :table
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :field
|
32
|
+
|
33
|
+
def columns
|
34
|
+
columns = Array(field)
|
35
|
+
columns = columns.first if columns.one?
|
36
|
+
|
37
|
+
columns
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|