mv-core 1.0.1 → 2.0.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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +67 -12
  3. data/lib/mv-core.rb +18 -100
  4. data/lib/mv/core/active_record/connection_adapters/abstract_adapter_decorator.rb +51 -0
  5. data/lib/mv/core/active_record/connection_adapters/table_decorator.rb +13 -0
  6. data/lib/mv/core/active_record/connection_adapters/table_definition_decorator.rb +21 -0
  7. data/lib/mv/core/active_record/migration/command_recorder_decorator.rb +13 -0
  8. data/lib/mv/core/active_record/migration_decorator.rb +14 -0
  9. data/lib/mv/core/active_record/schema_decorator.rb +16 -0
  10. data/lib/mv/core/active_record/schema_dumper_decorator.rb +29 -0
  11. data/lib/mv/core/constraint/base.rb +33 -0
  12. data/lib/mv/core/constraint/builder/base.rb +45 -0
  13. data/lib/mv/core/constraint/builder/factory.rb +42 -0
  14. data/lib/mv/core/constraint/builder/index.rb +50 -0
  15. data/lib/mv/core/constraint/builder/trigger.rb +13 -0
  16. data/lib/mv/core/constraint/description.rb +24 -0
  17. data/lib/mv/core/constraint/factory.rb +33 -0
  18. data/lib/mv/core/constraint/index.rb +13 -0
  19. data/lib/mv/core/constraint/trigger.rb +20 -0
  20. data/lib/mv/core/db/helpers/column_validators.rb +57 -0
  21. data/lib/mv/core/db/helpers/table_validators.rb +38 -0
  22. data/lib/mv/core/db/migration_validator.rb +26 -0
  23. data/lib/mv/core/error.rb +25 -0
  24. data/lib/mv/core/migration/base.rb +94 -0
  25. data/lib/mv/core/migration/operations/add_column.rb +27 -0
  26. data/lib/mv/core/migration/operations/change_column.rb +31 -0
  27. data/lib/mv/core/migration/operations/drop_table.rb +21 -0
  28. data/lib/mv/core/migration/operations/factory.rb +20 -0
  29. data/lib/mv/core/migration/operations/list.rb +28 -0
  30. data/lib/mv/core/migration/operations/remove_column.rb +22 -0
  31. data/lib/mv/core/migration/operations/rename_column.rb +26 -0
  32. data/lib/mv/core/migration/operations/rename_table.rb +25 -0
  33. data/lib/mv/core/presenter/constraint/description.rb +26 -0
  34. data/lib/mv/core/presenter/validation/base.rb +73 -0
  35. data/lib/mv/core/railtie.rb +40 -0
  36. data/lib/mv/core/route/base.rb +25 -0
  37. data/lib/mv/core/route/index.rb +17 -0
  38. data/lib/mv/core/route/trigger.rb +22 -0
  39. data/lib/mv/core/router.rb +33 -0
  40. data/lib/mv/core/services/compare_constraint_arrays.rb +50 -0
  41. data/lib/mv/core/services/compare_constraints.rb +31 -0
  42. data/lib/mv/core/services/create_constraints.rb +30 -0
  43. data/lib/mv/core/services/create_migration_validators_table.rb +31 -0
  44. data/lib/mv/core/services/delete_constraints.rb +30 -0
  45. data/lib/mv/core/services/load_constraints.rb +45 -0
  46. data/lib/mv/core/services/say_constraints_diff.rb +66 -0
  47. data/lib/mv/core/services/show_constraints.rb +41 -0
  48. data/lib/mv/core/services/synchronize_constraints.rb +54 -0
  49. data/lib/mv/core/services/uninstall.rb +25 -0
  50. data/lib/mv/core/validation/absence.rb +35 -0
  51. data/lib/mv/core/validation/base.rb +98 -0
  52. data/lib/mv/core/validation/builder/absence.rb +19 -0
  53. data/lib/mv/core/validation/builder/base.rb +58 -0
  54. data/lib/mv/core/validation/builder/exclusion.rb +42 -0
  55. data/lib/mv/core/validation/builder/factory.rb +43 -0
  56. data/lib/mv/core/validation/builder/inclusion.rb +42 -0
  57. data/lib/mv/core/validation/builder/length.rb +68 -0
  58. data/lib/mv/core/validation/builder/presence.rb +19 -0
  59. data/lib/mv/core/validation/builder/uniqueness.rb +19 -0
  60. data/lib/mv/core/validation/exclusion.rb +27 -0
  61. data/lib/mv/core/validation/factory.rb +56 -0
  62. data/lib/mv/core/validation/inclusion.rb +27 -0
  63. data/lib/mv/core/validation/length.rb +59 -0
  64. data/lib/mv/core/validation/presence.rb +25 -0
  65. data/lib/mv/core/validation/uniqueness.rb +45 -0
  66. data/lib/mv/core/validators/array_validator.rb +5 -0
  67. data/lib/mv/core/validators/integers_array_validator.rb +12 -0
  68. data/lib/mv/core/validators/valid_validator.rb +9 -0
  69. metadata +158 -30
  70. data/lib/migration_validators/active_record/base.rb +0 -29
  71. data/lib/migration_validators/active_record/connection_adapters/abstract_adapter.rb +0 -38
  72. data/lib/migration_validators/active_record/connection_adapters/native_adapter.rb +0 -129
  73. data/lib/migration_validators/active_record/connection_adapters/table.rb +0 -17
  74. data/lib/migration_validators/active_record/connection_adapters/table_definition.rb +0 -33
  75. data/lib/migration_validators/active_record/migration.rb +0 -25
  76. data/lib/migration_validators/active_record/schema.rb +0 -32
  77. data/lib/migration_validators/active_record/schema_dumper.rb +0 -25
  78. data/lib/migration_validators/adapters/base.rb +0 -15
  79. data/lib/migration_validators/adapters/containers.rb +0 -100
  80. data/lib/migration_validators/adapters/routing.rb +0 -102
  81. data/lib/migration_validators/adapters/syntax.rb +0 -51
  82. data/lib/migration_validators/adapters/validator_definitions.rb +0 -132
  83. data/lib/migration_validators/core/adapter_wrapper.rb +0 -88
  84. data/lib/migration_validators/core/db_validator.rb +0 -131
  85. data/lib/migration_validators/core/statement_builder.rb +0 -61
  86. data/lib/migration_validators/core/validator_constraints_list.rb +0 -32
  87. data/lib/migration_validators/core/validator_container.rb +0 -110
  88. data/lib/migration_validators/core/validator_definition.rb +0 -91
  89. data/lib/migration_validators/core/validator_router.rb +0 -45
  90. data/lib/options.rb +0 -7
@@ -0,0 +1,98 @@
1
+ module Mv
2
+ module Core
3
+ module Validation
4
+ class Base
5
+ include Comparable
6
+ include ActiveModel::Validations
7
+
8
+ attr_reader :table_name, :column_name, :message, :on, :create_trigger_name,
9
+ :update_trigger_name, :allow_nil, :allow_blank, :as, :options
10
+
11
+ validates :on, inclusion: { in: :available_on }, allow_nil: true
12
+ validates :allow_nil, :allow_blank, inclusion: { in: [true, false] }
13
+ validates :as, inclusion: { in: :available_as }
14
+
15
+ validates :on, absence: { message: 'allowed when :as == :trigger' }, unless: :trigger?
16
+ validates :create_trigger_name, absence: { message: 'allowed when :on in [:save, :create] and :as == :trigger'}, unless: "create? && trigger?"
17
+ validates :update_trigger_name, absence: { message: 'allowed when :on in [:save, :update] and :as == :trigger'}, unless: "update? && trigger?"
18
+
19
+ def initialize table_name, column_name, options
20
+ @table_name = table_name
21
+ @column_name = column_name
22
+ @options = options
23
+
24
+ options.with_indifferent_access.tap do |options|
25
+ @message = options[:message] || default_message
26
+ @as = options[:as] || default_as
27
+ @on = options[:on] || default_on
28
+ @create_trigger_name = options[:create_trigger_name] || default_create_trigger_name
29
+ @update_trigger_name = options[:update_trigger_name] || default_update_trigger_name
30
+ @allow_nil = options[:allow_nil].nil? ? default_allow_nil : options[:allow_nil]
31
+ @allow_blank = options[:allow_blank].nil? ? default_allow_blank : options[:allow_blank]
32
+ end
33
+ end
34
+
35
+ def to_a
36
+ [table_name.to_s, column_name.to_s, message.to_s, on.to_s, create_trigger_name.to_s,
37
+ update_trigger_name.to_s, allow_nil, allow_blank, as.to_s]
38
+ end
39
+
40
+ def <=> other_validation
41
+ [self.class.name, to_a] <=> [other_validation.class.name, other_validation.to_a]
42
+ end
43
+
44
+ def update?
45
+ [:save, :update].include?(on.try(:to_sym))
46
+ end
47
+
48
+ def create?
49
+ [:save, :create].include?(on.try(:to_sym))
50
+ end
51
+
52
+ protected
53
+
54
+ def available_as
55
+ [:trigger]
56
+ end
57
+
58
+ def available_on
59
+ [:save, :update, :create]
60
+ end
61
+
62
+ def default_message
63
+ "#{self.class.name.split('::').last} violated on the table #{table_name} column #{column_name}"
64
+ end
65
+
66
+ def default_on
67
+ :save if trigger?
68
+ end
69
+
70
+ def default_as
71
+ :trigger
72
+ end
73
+
74
+ def default_create_trigger_name
75
+ "trg_mv_#{table_name}_ins" if create? && trigger?
76
+ end
77
+
78
+ def default_update_trigger_name
79
+ "trg_mv_#{table_name}_upd" if update? && trigger?
80
+ end
81
+
82
+ def default_allow_nil
83
+ false
84
+ end
85
+
86
+ def default_allow_blank
87
+ false
88
+ end
89
+
90
+ private
91
+
92
+ def trigger?
93
+ as.try(:to_sym) == :trigger
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,19 @@
1
+ require 'mv/core/validation/builder/base'
2
+
3
+ module Mv
4
+ module Core
5
+ module Validation
6
+ module Builder
7
+ class Absence < Base
8
+ def conditions
9
+ null_stmt = "#{column_reference} #{allow_nil ? 'IS' : 'IS NOT'} NULL"
10
+ blank_stmt = "LENGTH(TRIM(#{column_reference})) #{allow_blank ? '=' : '>'} 0"
11
+ join_stmt = allow_nil && allow_blank ? 'OR' : 'AND'
12
+
13
+ [{ statement: [null_stmt, join_stmt, blank_stmt].join(' '), message: message }]
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,58 @@
1
+ module Mv
2
+ module Core
3
+ module Validation
4
+ module Builder
5
+ class Base
6
+ attr_reader :validation
7
+
8
+ delegate :table_name,
9
+ :column_name,
10
+ :message,
11
+ :allow_nil,
12
+ :allow_blank, to: :validation
13
+
14
+ def initialize(validation)
15
+ @validation = validation
16
+ end
17
+
18
+ protected
19
+
20
+ def column_reference
21
+ column_name
22
+ end
23
+
24
+ def apply_allow_nil_and_blank stmt
25
+ res = stmt
26
+
27
+ if allow_nil || allow_blank
28
+ if allow_nil
29
+ res = apply_allow_nil(res)
30
+ end
31
+
32
+ if allow_blank
33
+ res = apply_allow_nil(res) unless allow_nil
34
+ res = apply_allow_blank(res)
35
+ end
36
+ else
37
+ res = apply_neither_nil_or_blank_allowed(stmt)
38
+ end
39
+
40
+ res
41
+ end
42
+
43
+ def apply_allow_nil stmt
44
+ "#{stmt} OR #{column_reference} IS NULL"
45
+ end
46
+
47
+ def apply_allow_blank stmt
48
+ "#{stmt} OR LENGTH(TRIM(#{column_reference})) = 0"
49
+ end
50
+
51
+ def apply_neither_nil_or_blank_allowed stmt
52
+ "#{column_reference} IS NOT NULL AND #{stmt}"
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,42 @@
1
+ require 'mv/core/validation/builder/base'
2
+
3
+ module Mv
4
+ module Core
5
+ module Validation
6
+ module Builder
7
+ class Exclusion < Base
8
+ delegate :in, to: :validation
9
+
10
+ def conditions
11
+ [{
12
+ statement: apply_allow_nil_and_blank(apply_in(column_reference)),
13
+ message: message
14
+ }]
15
+ end
16
+
17
+ protected
18
+
19
+ def db_value value
20
+ return value if value.is_a?(Integer) or value.is_a?(Float)
21
+ return "'#{value.to_s}'" if value.is_a?(String)
22
+ raise Mv::Core::Error.new(table_name: table_name,
23
+ column_name: column_name,
24
+ validation_type: :inclusion,
25
+ options: { in: value },
26
+ error: "#{value.class} is not supported as :in value")
27
+ end
28
+
29
+ def apply_in stmt
30
+ if self.in.is_a?(Range)
31
+ "#{stmt} < #{db_value(self.in.min)} OR #{stmt} > #{db_value(self.in.max)}"
32
+ else
33
+ prepared_in = self.in.to_a.collect{ |v| db_value(v) }
34
+
35
+ "#{stmt} NOT IN (#{prepared_in.join(', ')})"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,43 @@
1
+ require 'mv/core/validation/builder/exclusion'
2
+ require 'mv/core/validation/builder/inclusion'
3
+ require 'mv/core/validation/builder/length'
4
+ require 'mv/core/validation/builder/presence'
5
+ require 'mv/core/validation/builder/absence'
6
+ require 'mv/core/validation/builder/uniqueness'
7
+
8
+ module Mv
9
+ module Core
10
+ module Validation
11
+ module Builder
12
+ class Factory
13
+ def create_builder validation
14
+ factory_map[validation.class].new(validation)
15
+ end
16
+
17
+ def register_builder validation_class, builder_class
18
+ factory_map[validation_class] = builder_class
19
+ end
20
+
21
+ def register_builders opts
22
+ opts.each do |validation_class, builder_class|
23
+ register_builder(validation_class, builder_class)
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def factory_map
30
+ @factory_map ||= {
31
+ Mv::Core::Validation::Exclusion => Mv::Core::Validation::Builder::Exclusion,
32
+ Mv::Core::Validation::Inclusion => Mv::Core::Validation::Builder::Inclusion,
33
+ Mv::Core::Validation::Length => Mv::Core::Validation::Builder::Length,
34
+ Mv::Core::Validation::Presence => Mv::Core::Validation::Builder::Presence,
35
+ Mv::Core::Validation::Absence => Mv::Core::Validation::Builder::Absence,
36
+ Mv::Core::Validation::Uniqueness => Mv::Core::Validation::Builder::Uniqueness
37
+ }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,42 @@
1
+ require 'mv/core/validation/builder/base'
2
+
3
+ module Mv
4
+ module Core
5
+ module Validation
6
+ module Builder
7
+ class Inclusion < Base
8
+ delegate :in, to: :validation
9
+
10
+ def conditions
11
+ [{
12
+ statement: apply_allow_nil_and_blank(apply_in(column_reference)),
13
+ message: message
14
+ }]
15
+ end
16
+
17
+ protected
18
+
19
+ def db_value value
20
+ return value if value.is_a?(Integer) or value.is_a?(Float)
21
+ return "'#{value.to_s}'" if value.is_a?(String)
22
+ raise Mv::Core::Error.new(table_name: table_name,
23
+ column_name: column_name,
24
+ validation_type: :inclusion,
25
+ options: { in: value },
26
+ error: "#{value.class} is not supported as :in value")
27
+ end
28
+
29
+ def apply_in stmt
30
+ if self.in.is_a?(Range)
31
+ "#{stmt} BETWEEN #{db_value(self.in.min)} AND #{db_value(self.in.max)}"
32
+ else
33
+ prepared_in = self.in.to_a.collect{ |v| db_value(v) }
34
+
35
+ "#{stmt} IN (#{prepared_in.join(', ')})"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,68 @@
1
+ require 'mv/core/validation/builder/base'
2
+
3
+ module Mv
4
+ module Core
5
+ module Validation
6
+ module Builder
7
+ class Length < Base
8
+ delegate :in,
9
+ :within,
10
+ :is,
11
+ :maximum,
12
+ :minimum,
13
+ :too_short,
14
+ :too_long,
15
+ to: :validation
16
+
17
+ def conditions
18
+ res = apply_in(column_reference) if self.in
19
+ res = apply_within(column_reference) if within
20
+ res = apply_is(column_reference) if self.is
21
+ res = apply_maximum(column_reference) if maximum && !minimum
22
+ res = apply_minimum(column_reference) if minimum && !maximum
23
+ res = apply_minimum_and_maximum(column_reference) if minimum && maximum
24
+
25
+ res.collect do |condition|
26
+ { statement: apply_allow_nil_and_blank(condition[:statement]), message: condition[:message] }
27
+ end
28
+ end
29
+
30
+ protected
31
+
32
+ def apply_in stmt
33
+ [{ statement: self.in.is_a?(Range) ? "LENGTH(#{stmt}) BETWEEN #{self.in.min} AND #{self.in.max}" :
34
+ "LENGTH(#{stmt}) IN (#{self.in.join(', ')})",
35
+ message: message }]
36
+ end
37
+
38
+ def apply_within stmt
39
+ [{ statement: within.is_a?(Range) ? "LENGTH(#{stmt}) BETWEEN #{within.min} AND #{within.max}" :
40
+ "LENGTH(#{stmt}) IN (#{within.join(', ')})",
41
+ message: message }]
42
+ end
43
+
44
+ def apply_is stmt
45
+ [{ statement: "LENGTH(#{stmt}) = #{self.is}", message: message }]
46
+ end
47
+
48
+ def apply_maximum stmt
49
+ [{ statement: "LENGTH(#{stmt}) <= #{maximum}", message: too_long || message }]
50
+ end
51
+
52
+ def apply_minimum stmt
53
+ [{ statement: "LENGTH(#{stmt}) >= #{minimum}", message: too_short || message }]
54
+ end
55
+
56
+ def apply_minimum_and_maximum stmt
57
+ if too_long == too_short
58
+ [{ statement: "LENGTH(#{stmt}) BETWEEN #{minimum} AND #{maximum}",
59
+ message: message }]
60
+ else
61
+ [apply_minimum(stmt), apply_maximum(stmt)].flatten
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,19 @@
1
+ require 'mv/core/validation/builder/base'
2
+
3
+ module Mv
4
+ module Core
5
+ module Validation
6
+ module Builder
7
+ class Presence < Base
8
+ def conditions
9
+ null_stmt = "#{column_reference} #{allow_nil ? 'IS' : 'IS NOT'} NULL"
10
+ blank_stmt = "LENGTH(TRIM(#{column_reference})) #{allow_blank ? '=' : '>'} 0"
11
+ join_stmt = allow_nil || allow_blank ? 'OR' : 'AND'
12
+
13
+ [{ statement: [null_stmt, join_stmt, blank_stmt].join(' '), message: message }]
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ require 'mv/core/validation/builder/base'
2
+
3
+ module Mv
4
+ module Core
5
+ module Validation
6
+ module Builder
7
+ class Uniqueness < Base
8
+ def conditions
9
+ res = "NOT EXISTS(SELECT #{column_name}
10
+ FROM #{table_name}
11
+ WHERE #{column_reference} = #{column_name})"
12
+
13
+ [{statement: apply_allow_nil_and_blank(res).squish, message: message}]
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ require 'mv/core/validation/base'
2
+ require 'mv/core/validators/array_validator'
3
+
4
+ module Mv
5
+ module Core
6
+ module Validation
7
+ class Exclusion < Base
8
+ include ActiveModel::Validations
9
+
10
+ attr_reader :in
11
+
12
+ validates :in, presence: true, array: true
13
+
14
+ def initialize(table_name, column_name, opts)
15
+ super(table_name, column_name, opts)
16
+
17
+ @in = opts.with_indifferent_access[:in]
18
+ end
19
+
20
+ def to_a
21
+ prepared_in = self.in.is_a?(Range) ? [self.in.min, self.in.max] : self.in.try(:sort)
22
+ super + [prepared_in]
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end