nandi 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|