dynamic_migrations 3.5.2 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (26) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/lib/dynamic_migrations/active_record/migrators/trigger.rb +12 -12
  4. data/lib/dynamic_migrations/postgres/generator/trigger.rb +83 -49
  5. data/lib/dynamic_migrations/postgres/generator/trigger_template_base.rb +38 -0
  6. data/lib/dynamic_migrations/postgres/generator/validation.rb +68 -33
  7. data/lib/dynamic_migrations/postgres/generator/validation_template_base.rb +74 -0
  8. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/extensions.rb +2 -2
  9. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/enums.rb +2 -2
  10. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/functions.rb +2 -2
  11. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables.rb +2 -2
  12. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas.rb +2 -2
  13. data/lib/dynamic_migrations/postgres/server/database/schema/table/trigger.rb +12 -1
  14. data/lib/dynamic_migrations/postgres/server/database/schema/table/triggers.rb +2 -2
  15. data/lib/dynamic_migrations/postgres/server/database/schema/table/validation.rb +12 -1
  16. data/lib/dynamic_migrations/version.rb +1 -1
  17. data/lib/dynamic_migrations.rb +2 -0
  18. data/sig/dynamic_migrations/active_record/migrators/trigger.rbs +7 -2
  19. data/sig/dynamic_migrations/postgres/generator/trigger.rbs +11 -2
  20. data/sig/dynamic_migrations/postgres/generator/trigger_template_base.rbs +25 -0
  21. data/sig/dynamic_migrations/postgres/generator/validation.rbs +12 -0
  22. data/sig/dynamic_migrations/postgres/generator/validation_template_base.rbs +30 -0
  23. data/sig/dynamic_migrations/postgres/server/database/schema/table/trigger.rbs +5 -1
  24. data/sig/dynamic_migrations/postgres/server/database/schema/table/triggers.rbs +1 -1
  25. data/sig/dynamic_migrations/postgres/server/database/schema/table/validation.rbs +6 -1
  26. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d618a9b98ed9b0f378f6e4342c57e6df554df34c600572a6aa55db61dbb32fad
4
- data.tar.gz: a90d7e5fa28aa0f4dbc2d42a7545ed6207bc800baba766dd23c9bc0e73cfd0c6
3
+ metadata.gz: a25d76d54d7129a77f16574c4b6a84cf82ca6105afe4279ba868b34b97fa4814
4
+ data.tar.gz: b60f87c21dd0e53aed9853d4eaece239cab1d2524ba9c500e3dc364eda1d40dd
5
5
  SHA512:
6
- metadata.gz: 33c0b803f4a4a01aff67b258ade285c2acf0420c0c611b918cf24405f5081497050bdcb726532b01fe4d832a086d15a4b37dc5a03c445772e7b6e863edd795c6
7
- data.tar.gz: 7a00457cdb78107f62c43bd74647513817c1fbb0e4dbbc92bdc458aefc02030980fd074d03f2ada4399dd442f4152098024a492839fe98ccba2ad16ad4508356
6
+ metadata.gz: ef75931965eb2dd877bd22a82b4ad6532df5ab4e9e5ff24cc160f9fcc81c3c1db7eca2698b30da99a29000c7c67cf4efd1f5d7eca8ff28fbcc31631a0d43225b
7
+ data.tar.gz: 4d4218e2872b79b68b79517696403f3aa15c1b87ac2c9b8afd47e1ebb4a1fcb1b3e3efbd0f0db61ad788e8c80472b2eef1d389e08dbf0153414dcfecab5b976c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.6.0](https://github.com/craigulliott/dynamic_migrations/compare/v3.5.3...v3.6.0) (2023-09-13)
4
+
5
+
6
+ ### Features
7
+
8
+ * plugin architecture for validation and trigger templates (allows for creating cleaner migrations with custom methods) ([f4e9d5e](https://github.com/craigulliott/dynamic_migrations/commit/f4e9d5eae803196e727a5b4d7314e773cd90ba00))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * fixed badly generated trigger migration ([f4e9d5e](https://github.com/craigulliott/dynamic_migrations/commit/f4e9d5eae803196e727a5b4d7314e773cd90ba00))
14
+
15
+ ## [3.5.3](https://github.com/craigulliott/dynamic_migrations/compare/v3.5.2...v3.5.3) (2023-09-11)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * accepting nil or false for existence check when calculating differences (because if the schema doesn't exist we wont have table objects to test against) ([de63879](https://github.com/craigulliott/dynamic_migrations/commit/de638791035a0a1ad4658149777aa6e2ac7dc2ed))
21
+
3
22
  ## [3.5.2](https://github.com/craigulliott/dynamic_migrations/compare/v3.5.1...v3.5.2) (2023-09-11)
4
23
 
5
24
 
@@ -62,28 +62,28 @@ module DynamicMigrations
62
62
  end
63
63
 
64
64
  # wrappers for add_trigger which provide more friendly syntax
65
- def before_insert table_name, name:, function_schema_name:, function_name:, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, comment: nil
66
- add_trigger table_name, name: name, action_timing: :before, event_manipulation: :insert, action_orientation: :row, function_schema_name: function_schema_name, function_name: function_name, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, comment: comment
65
+ def before_insert table_name, name:, function_schema_name:, function_name:, parameters: nil, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, comment: nil
66
+ add_trigger table_name, name: name, action_timing: :before, event_manipulation: :insert, action_orientation: :row, function_schema_name: function_schema_name, function_name: function_name, parameters: parameters, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, comment: comment
67
67
  end
68
68
 
69
- def before_update table_name, name:, function_schema_name:, function_name:, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, comment: nil
70
- add_trigger table_name, name: name, action_timing: :before, event_manipulation: :update, action_orientation: :row, function_schema_name: function_schema_name, function_name: function_name, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, comment: comment
69
+ def before_update table_name, name:, function_schema_name:, function_name:, parameters: nil, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, comment: nil
70
+ add_trigger table_name, name: name, action_timing: :before, event_manipulation: :update, action_orientation: :row, function_schema_name: function_schema_name, function_name: function_name, parameters: parameters, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, comment: comment
71
71
  end
72
72
 
73
- def before_delete table_name, name:, function_schema_name:, function_name:, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, comment: nil
74
- add_trigger table_name, name: name, action_timing: :before, event_manipulation: :delete, action_orientation: :row, function_schema_name: function_schema_name, function_name: function_name, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, comment: comment
73
+ def before_delete table_name, name:, function_schema_name:, function_name:, parameters: nil, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, comment: nil
74
+ add_trigger table_name, name: name, action_timing: :before, event_manipulation: :delete, action_orientation: :row, function_schema_name: function_schema_name, function_name: function_name, parameters: parameters, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, comment: comment
75
75
  end
76
76
 
77
- def after_insert table_name, name:, function_schema_name:, function_name:, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, comment: nil
78
- add_trigger table_name, name: name, action_timing: :after, event_manipulation: :insert, action_orientation: :row, function_schema_name: function_schema_name, function_name: function_name, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, comment: comment
77
+ def after_insert table_name, name:, function_schema_name:, function_name:, parameters: nil, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, comment: nil
78
+ add_trigger table_name, name: name, action_timing: :after, event_manipulation: :insert, action_orientation: :row, function_schema_name: function_schema_name, function_name: function_name, parameters: parameters, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, comment: comment
79
79
  end
80
80
 
81
- def after_update table_name, name:, function_schema_name:, function_name:, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, comment: nil
82
- add_trigger table_name, name: name, action_timing: :after, event_manipulation: :update, action_orientation: :row, function_schema_name: function_schema_name, function_name: function_name, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, comment: comment
81
+ def after_update table_name, name:, function_schema_name:, function_name:, parameters: nil, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, comment: nil
82
+ add_trigger table_name, name: name, action_timing: :after, event_manipulation: :update, action_orientation: :row, function_schema_name: function_schema_name, function_name: function_name, parameters: parameters, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, comment: comment
83
83
  end
84
84
 
85
- def after_delete table_name, name:, function_schema_name:, function_name:, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, comment: nil
86
- add_trigger table_name, name: name, action_timing: :after, event_manipulation: :delete, action_orientation: :row, function_schema_name: function_schema_name, function_name: function_name, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, comment: comment
85
+ def after_delete table_name, name:, function_schema_name:, function_name:, parameters: nil, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, comment: nil
86
+ add_trigger table_name, name: name, action_timing: :after, event_manipulation: :delete, action_orientation: :row, function_schema_name: function_schema_name, function_name: function_name, parameters: parameters, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, comment: comment
87
87
  end
88
88
 
89
89
  def remove_trigger table_name, trigger_name
@@ -2,62 +2,96 @@ module DynamicMigrations
2
2
  module Postgres
3
3
  class Generator
4
4
  module Trigger
5
- def add_trigger trigger, code_comment = nil
6
- options = {
7
- name: ":#{trigger.name}"
8
- }
9
-
10
- # if the trigger is a row trigger and the action timing is before or after
11
- # then we can use some syntactic sugar to make the migration look nicer
12
- # we use method names like before_insert, after_update, etc. and drop the
13
- # unnessessary options
14
- if trigger.action_orientation == :row && [:before, :after].include?(trigger.action_timing)
15
- method_name = "#{trigger.action_timing}_#{trigger.event_manipulation}"
16
- else
17
- method_name = "add_trigger"
18
- options[:action_timing] = ":#{trigger.action_timing}"
19
- options[:event_manipulation] = ":#{trigger.event_manipulation}"
20
- options[:action_orientation] = ":#{trigger.action_orientation}"
21
- end
22
-
23
- # added here because we want the timing and manipulation to visually appear first
24
- options[:function_schema_name] = ":#{trigger.function.schema.name}"
25
- options[:function_name] = ":#{trigger.function.name}"
5
+ class UnexpectedTemplateError < StandardError
6
+ end
26
7
 
27
- unless trigger.action_condition.nil?
28
- options[:action_condition] = ":#{trigger.action_condition}"
29
- end
8
+ class TemplateAlreadyExistsError < StandardError
9
+ end
30
10
 
31
- unless trigger.parameters.nil?
32
- options[:parameters] = "\"#{trigger.parameters}\""
33
- end
11
+ def self.template template_name
12
+ @templates && @templates[template_name]
13
+ end
34
14
 
35
- unless trigger.action_reference_old_table.nil?
36
- options[:action_reference_old_table] = ":#{trigger.action_reference_old_table}"
37
- end
15
+ def self.has_template? template_name
16
+ @templates&.key?(template_name) || false
17
+ end
38
18
 
39
- unless trigger.action_reference_new_table.nil?
40
- options[:action_reference_new_table] = ":#{trigger.action_reference_new_table}"
41
- end
19
+ # install a template into the migration generator, this can be used from outside this
20
+ # library to clean up common migrations (replace common migrations with syntatic sugar)
21
+ def self.add_template name, template_class
22
+ @templates ||= {}
23
+ raise TemplateAlreadyExistsError, name if @templates.key?(name)
24
+ @templates[name] = template_class
25
+ end
42
26
 
43
- unless trigger.description.nil?
44
- options[:comment] = <<~RUBY
45
- <<~COMMENT
46
- #{indent trigger.description}
47
- COMMENT
48
- RUBY
49
- end
27
+ def add_trigger trigger, code_comment = nil
28
+ # if we have a corresponding template, then use it
29
+ if trigger.template
30
+ unless (template_class = Trigger.template(trigger.template))
31
+ raise UnexpectedTemplateError, "Unrecognised template #{trigger.template}"
32
+ end
50
33
 
51
- options_syntax = options.map { |k, v| "#{k}: #{v}" }.join(", ")
34
+ arguments = template_class.new(trigger, code_comment).fragment_arguments
35
+ add_fragment(**arguments)
52
36
 
53
- add_fragment schema: trigger.table.schema,
54
- table: trigger.table,
55
- migration_method: :add_trigger,
56
- object: trigger,
57
- code_comment: code_comment,
58
- migration: <<~RUBY
59
- #{method_name} :#{trigger.table.name}, #{options_syntax}
60
- RUBY
37
+ # no template, process this as a default trigger (takes all options)
38
+ else
39
+ options = {
40
+ name: ":#{trigger.name}"
41
+ }
42
+
43
+ # if the trigger is a row trigger and the action timing is before or after
44
+ # then we can use some syntactic sugar to make the migration look nicer
45
+ # we use method names like before_insert, after_update, etc. and drop the
46
+ # unnessessary options
47
+ if trigger.action_orientation == :row && [:before, :after].include?(trigger.action_timing)
48
+ method_name = "#{trigger.action_timing}_#{trigger.event_manipulation}"
49
+ else
50
+ method_name = "add_trigger"
51
+ options[:action_timing] = ":#{trigger.action_timing}"
52
+ options[:event_manipulation] = ":#{trigger.event_manipulation}"
53
+ options[:action_orientation] = ":#{trigger.action_orientation}"
54
+ end
55
+
56
+ # added here because we want the timing and manipulation to visually appear first
57
+ options[:function_schema_name] = ":#{trigger.function.schema.name}"
58
+ options[:function_name] = ":#{trigger.function.name}"
59
+
60
+ unless trigger.action_condition.nil?
61
+ options[:action_condition] = "\"#{trigger.action_condition}\""
62
+ end
63
+
64
+ unless trigger.parameters.nil?
65
+ options[:parameters] = "\"#{trigger.parameters}\""
66
+ end
67
+
68
+ unless trigger.action_reference_old_table.nil?
69
+ options[:action_reference_old_table] = ":#{trigger.action_reference_old_table}"
70
+ end
71
+
72
+ unless trigger.action_reference_new_table.nil?
73
+ options[:action_reference_new_table] = ":#{trigger.action_reference_new_table}"
74
+ end
75
+
76
+ unless trigger.description.nil?
77
+ options[:comment] = <<~RUBY
78
+ <<~COMMENT
79
+ #{indent trigger.description}
80
+ COMMENT
81
+ RUBY
82
+ end
83
+
84
+ options_syntax = options.map { |k, v| "#{k}: #{v}" }.join(", ")
85
+
86
+ add_fragment schema: trigger.table.schema,
87
+ table: trigger.table,
88
+ migration_method: :add_trigger,
89
+ object: trigger,
90
+ code_comment: code_comment,
91
+ migration: <<~RUBY
92
+ #{method_name} :#{trigger.table.name}, #{options_syntax}
93
+ RUBY
94
+ end
61
95
  end
62
96
 
63
97
  def remove_trigger trigger, code_comment = nil
@@ -0,0 +1,38 @@
1
+ module DynamicMigrations
2
+ module Postgres
3
+ class Generator
4
+ class TriggerTemplateBase
5
+ class TemplateError < StandardError
6
+ end
7
+
8
+ attr_reader :trigger
9
+
10
+ def initialize trigger, code_comment
11
+ @trigger = trigger
12
+ @code_comment = code_comment
13
+ end
14
+
15
+ private
16
+
17
+ def assert_column_count! count = 1
18
+ if @trigger.columns.count != count
19
+ raise TemplateError, "#{self.class.name} trigger template requires a trigger with only #{count} column"
20
+ end
21
+ end
22
+
23
+ def first_column
24
+ column = @trigger.columns.first
25
+ if column.nil?
26
+ raise TemplateError, "#{self.class.name} trigger template requires a first column"
27
+ end
28
+ column
29
+ end
30
+
31
+ def indent multi_line_string, levels = 1
32
+ spaces = " " * levels
33
+ multi_line_string.gsub("\n", "\n#{spaces}")
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -2,44 +2,79 @@ module DynamicMigrations
2
2
  module Postgres
3
3
  class Generator
4
4
  module Validation
5
+ class UnexpectedTemplateError < StandardError
6
+ end
7
+
8
+ class TemplateAlreadyExistsError < StandardError
9
+ end
10
+
11
+ def self.template template_name
12
+ @templates && @templates[template_name]
13
+ end
14
+
15
+ def self.has_template? template_name
16
+ @templates&.key?(template_name) || false
17
+ end
18
+
19
+ # install a template into the migration generator, this can be used from outside this
20
+ # library to clean up common migrations (replace common migrations with syntatic sugar)
21
+ def self.add_template name, template_class
22
+ @templates ||= {}
23
+ raise TemplateAlreadyExistsError, name if @templates.key?(name)
24
+ @templates[name] = template_class
25
+ end
26
+
5
27
  def add_validation validation, code_comment = nil
6
- options = {
7
- name: ":#{validation.name}",
8
- deferrable: validation.deferrable,
9
- initially_deferred: validation.initially_deferred
10
- }
11
-
12
- if validation.description.nil?
13
- comment_sql = ""
28
+ # if we have a corresponding template, then use it
29
+ if validation.template
30
+ unless (template_class = Validation.template(validation.template))
31
+ raise UnexpectedTemplateError, "Unrecognised template #{validation.template}"
32
+ end
33
+
34
+ arguments = template_class.new(validation, code_comment).fragment_arguments
35
+ add_fragment(**arguments)
36
+
37
+ # no template, process this as a default validation (takes all options)
14
38
  else
15
- comment_sql = <<~RUBY
16
- #{validation.name}_comment = <<~COMMENT
17
- #{indent validation.description || ""}
18
- COMMENT
19
- RUBY
20
- options[:comment] = "#{validation.name}_comment"
21
- end
22
39
 
23
- options_syntax = options.map { |k, v| "#{k}: #{v}" }.join(", ")
40
+ options = {
41
+ name: ":#{validation.name}",
42
+ deferrable: validation.deferrable,
43
+ initially_deferred: validation.initially_deferred
44
+ }
24
45
 
25
- validation_sql = validation.check_clause.strip
26
- # ensure that the validation ends with a semicolon
27
- unless validation_sql.end_with? ";"
28
- validation_sql << ";"
29
- end
46
+ if validation.description.nil?
47
+ comment_sql = ""
48
+ else
49
+ comment_sql = <<~RUBY
50
+ #{validation.name}_comment = <<~COMMENT
51
+ #{indent validation.description || ""}
52
+ COMMENT
53
+ RUBY
54
+ options[:comment] = "#{validation.name}_comment"
55
+ end
30
56
 
31
- add_fragment schema: validation.table.schema,
32
- table: validation.table,
33
- migration_method: :add_validation,
34
- object: validation,
35
- code_comment: code_comment,
36
- migration: comment_sql + <<~RUBY
37
- add_validation :#{validation.table.name}, #{options_syntax} do
38
- <<~SQL
39
- #{indent validation_sql}
40
- SQL
41
- end
42
- RUBY
57
+ options_syntax = options.map { |k, v| "#{k}: #{v}" }.join(", ")
58
+
59
+ validation_sql = validation.check_clause.strip
60
+ # ensure that the validation ends with a semicolon
61
+ unless validation_sql.end_with? ";"
62
+ validation_sql << ";"
63
+ end
64
+
65
+ add_fragment schema: validation.table.schema,
66
+ table: validation.table,
67
+ migration_method: :add_validation,
68
+ object: validation,
69
+ code_comment: code_comment,
70
+ migration: comment_sql + <<~RUBY
71
+ add_validation :#{validation.table.name}, #{options_syntax} do
72
+ <<~SQL
73
+ #{indent validation_sql}
74
+ SQL
75
+ end
76
+ RUBY
77
+ end
43
78
  end
44
79
 
45
80
  def remove_validation validation, code_comment = nil
@@ -0,0 +1,74 @@
1
+ module DynamicMigrations
2
+ module Postgres
3
+ class Generator
4
+ class ValidationTemplateBase
5
+ class TemplateError < StandardError
6
+ end
7
+
8
+ attr_reader :validation
9
+
10
+ def initialize validation, code_comment
11
+ @validation = validation
12
+ @code_comment = code_comment
13
+ end
14
+
15
+ private
16
+
17
+ def assert_not_deferred!
18
+ if @validation.initially_deferred || @validation.deferrable
19
+ raise TemplateError, "#{self.class.name} validation template requires constraints to be are not deferrable"
20
+ end
21
+ end
22
+
23
+ def assert_column_count! count = 1
24
+ if @validation.columns.count != count
25
+ raise TemplateError, "#{self.class.name} validation template requires a validation with only #{count} column"
26
+ end
27
+ end
28
+
29
+ def first_column
30
+ column = @validation.columns.first
31
+ if column.nil?
32
+ raise TemplateError, "#{self.class.name} validation template requires a first column"
33
+ end
34
+ column
35
+ end
36
+
37
+ def value_from_check_clause regex
38
+ matches = @validation.check_clause.strip.match(regex)
39
+ unless matches
40
+ raise TemplateError, "#{self.class.name} validation template check_clause was not an expected format"
41
+ end
42
+ if matches[:value].nil?
43
+ raise TemplateError, "#{self.class.name} validation template check_clause could not parse out value from regex (expected `value` named capture group in the regex)"
44
+ end
45
+ matches[:value]
46
+ end
47
+
48
+ def name_and_description_options_string default_name
49
+ options = {}
50
+ # we only need to provide a name if it is different than the default
51
+ unless @validation.name == default_name
52
+ options[:name] = @validation.name
53
+ end
54
+ # only provide a comment if it is not nil
55
+ unless @validation.description.nil?
56
+ options[:comment] = <<~RUBY
57
+ <<~COMMENT
58
+ #{indent @validation.description || ""}
59
+ COMMENT
60
+ RUBY
61
+ end
62
+
63
+ options_string = options.map { |k, v| "#{k}: #{v}" }.join(", ")
64
+ options_string.empty? ? nil : ", #{options_string}"
65
+ end
66
+
67
+ def indent multi_line_string, levels = 1
68
+ spaces = " " * levels
69
+ multi_line_string.gsub("\n", "\n#{spaces}")
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -10,13 +10,13 @@ module DynamicMigrations
10
10
  def process_extension extension_name, configuration_extension, database_extension
11
11
  # if the extension exists in the configuration but not in the database
12
12
  # then we have to create it
13
- if configuration_extension[:exists] == true && database_extension[:exists] == false
13
+ if configuration_extension[:exists] == true && !database_extension[:exists]
14
14
  # a migration to create the extension
15
15
  @generator.create_extension extension_name
16
16
 
17
17
  # if the extension exists in the database but not in the configuration
18
18
  # then we need to delete it
19
- elsif configuration_extension[:exists] == false && database_extension[:exists] == true
19
+ elsif database_extension[:exists] == true && !configuration_extension[:exists]
20
20
  # a migration to drop the extension
21
21
  @generator.drop_extension extension_name
22
22
  end
@@ -19,7 +19,7 @@ module DynamicMigrations
19
19
  def process_enum schema_name, enum_name, configuration_enum, database_enum
20
20
  # If the enum exists in the configuration but not in the database
21
21
  # then we have to create it.
22
- if configuration_enum[:exists] == true && database_enum[:exists] == false
22
+ if configuration_enum[:exists] == true && !database_enum[:exists]
23
23
  # a migration to create the enum
24
24
  enum = @database.configured_schema(schema_name).enum(enum_name)
25
25
  @generator.create_enum enum
@@ -30,7 +30,7 @@ module DynamicMigrations
30
30
 
31
31
  # If the schema exists in the database but not in the configuration
32
32
  # then we need to delete it.
33
- elsif configuration_enum[:exists] == false && database_enum[:exists] == true
33
+ elsif database_enum[:exists] == true && !configuration_enum[:exists]
34
34
  # a migration to create the enum
35
35
  enum = @database.loaded_schema(schema_name).enum(enum_name)
36
36
  @generator.drop_enum enum
@@ -19,14 +19,14 @@ module DynamicMigrations
19
19
  def process_function schema_name, function_name, configuration_function, database_function
20
20
  # If the function exists in the configuration but not in the database
21
21
  # then we have to create it.
22
- if configuration_function[:exists] == true && database_function[:exists] == false
22
+ if configuration_function[:exists] == true && !database_function[:exists]
23
23
  # a migration to create the function
24
24
  function = @database.configured_schema(schema_name).function(function_name)
25
25
  @generator.create_function function
26
26
 
27
27
  # If the schema exists in the database but not in the configuration
28
28
  # then we need to delete it.
29
- elsif configuration_function[:exists] == false && database_function[:exists] == true
29
+ elsif database_function[:exists] == true && !configuration_function[:exists]
30
30
  # a migration to create the function
31
31
  function = @database.loaded_schema(schema_name).function(function_name)
32
32
  @generator.drop_function function
@@ -19,7 +19,7 @@ module DynamicMigrations
19
19
  def process_table schema_name, table_name, configuration_table, database_table
20
20
  # If the table exists in the configuration but not in the database
21
21
  # then we have to create it.
22
- if configuration_table[:exists] == true && database_table[:exists] == false
22
+ if configuration_table[:exists] == true && !database_table[:exists]
23
23
  # a migration to create the table
24
24
  table = @database.configured_schema(schema_name).table(table_name)
25
25
  @generator.create_table table
@@ -30,7 +30,7 @@ module DynamicMigrations
30
30
 
31
31
  # If the schema exists in the database but not in the configuration
32
32
  # then we need to delete it.
33
- elsif configuration_table[:exists] == false && database_table[:exists] == true
33
+ elsif database_table[:exists] == true && !configuration_table[:exists]
34
34
  # we process everything else before we drop the table, because the other
35
35
  # database objects are dependent on the table
36
36
  process_dependents schema_name, table_name, {}, database_table
@@ -10,7 +10,7 @@ module DynamicMigrations
10
10
  def process_schema schema_name, configuration_schema, database_schema
11
11
  # if the schema exists in the configuration but not in the database
12
12
  # then we have to create it
13
- if configuration_schema[:exists] == true && database_schema[:exists] == false
13
+ if configuration_schema[:exists] == true && !database_schema[:exists]
14
14
  # a migration to create the schema
15
15
  schema = @database.configured_schema schema_name
16
16
  @generator.create_schema schema
@@ -23,7 +23,7 @@ module DynamicMigrations
23
23
 
24
24
  # if the schema exists in the database but not in the configuration
25
25
  # then we need to delete it
26
- elsif configuration_schema[:exists] == false && database_schema[:exists] == true
26
+ elsif database_schema[:exists] == true && !configuration_schema[:exists]
27
27
  # we process the tables and functions before we drop the schema
28
28
  # as this will drop any dependencies on the schema
29
29
  process_functions schema_name, {}, database_schema[:functions]
@@ -35,6 +35,9 @@ module DynamicMigrations
35
35
  class UnexpectedActionOrderError < StandardError
36
36
  end
37
37
 
38
+ class UnexpectedTemplateError < StandardError
39
+ end
40
+
38
41
  attr_reader :table
39
42
  attr_reader :name
40
43
  attr_reader :event_manipulation
@@ -46,9 +49,10 @@ module DynamicMigrations
46
49
  attr_reader :action_reference_old_table
47
50
  attr_reader :action_reference_new_table
48
51
  attr_reader :description
52
+ attr_reader :template
49
53
 
50
54
  # initialize a new object to represent a validation in a postgres table
51
- def initialize source, table, name, action_timing:, event_manipulation:, parameters:, action_orientation:, function:, action_order: nil, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, description: nil
55
+ def initialize source, table, name, action_timing:, event_manipulation:, parameters:, action_orientation:, function:, action_order: nil, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, description: nil, template: nil
52
56
  super source
53
57
 
54
58
  unless table.is_a? Table
@@ -125,6 +129,13 @@ module DynamicMigrations
125
129
  @description = description.strip
126
130
  @description = nil if description == ""
127
131
  end
132
+
133
+ unless template.nil?
134
+ unless Generator::Trigger.has_template? template
135
+ raise UnexpectedTemplateError, template
136
+ end
137
+ @template = template
138
+ end
128
139
  end
129
140
 
130
141
  def action_order
@@ -38,13 +38,13 @@ module DynamicMigrations
38
38
  end
39
39
 
40
40
  # adds a new trigger to this table, and returns it
41
- def add_trigger name, action_timing:, event_manipulation:, parameters:, action_orientation:, function:, action_order: nil, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, description: nil
41
+ def add_trigger name, action_timing:, event_manipulation:, parameters:, action_orientation:, function:, action_order: nil, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, description: nil, template: nil
42
42
  if has_trigger? name
43
43
  raise(TriggerAlreadyExistsError, "Trigger #{name} already exists")
44
44
  end
45
45
  included_target = self
46
46
  if included_target.is_a? Table
47
- new_trigger = @triggers[name] = Trigger.new source, included_target, name, action_timing: action_timing, event_manipulation: event_manipulation, action_order: action_order, parameters: parameters, action_orientation: action_orientation, function: function, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, description: description
47
+ new_trigger = @triggers[name] = Trigger.new source, included_target, name, action_timing: action_timing, event_manipulation: event_manipulation, action_order: action_order, parameters: parameters, action_orientation: action_orientation, function: function, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, description: description, template: template
48
48
  else
49
49
  raise ModuleIncludedIntoUnexpectedTargetError, included_target
50
50
  end
@@ -17,15 +17,19 @@ module DynamicMigrations
17
17
  class DuplicateColumnError < StandardError
18
18
  end
19
19
 
20
+ class UnexpectedTemplateError < StandardError
21
+ end
22
+
20
23
  attr_reader :table
21
24
  attr_reader :name
22
25
  attr_reader :check_clause
23
26
  attr_reader :deferrable
24
27
  attr_reader :initially_deferred
25
28
  attr_reader :description
29
+ attr_reader :template
26
30
 
27
31
  # initialize a new object to represent a validation in a postgres table
28
- def initialize source, table, columns, name, check_clause, description: nil, deferrable: false, initially_deferred: false
32
+ def initialize source, table, columns, name, check_clause, description: nil, deferrable: false, initially_deferred: false, template: nil
29
33
  super source
30
34
  raise ExpectedTableError, table unless table.is_a? Table
31
35
  @table = table
@@ -57,6 +61,13 @@ module DynamicMigrations
57
61
 
58
62
  raise ExpectedBooleanError, initially_deferred unless [true, false].include?(initially_deferred)
59
63
  @initially_deferred = initially_deferred
64
+
65
+ unless template.nil?
66
+ unless Generator::Validation.has_template? template
67
+ raise UnexpectedTemplateError, "Unrecognised template #{template}"
68
+ end
69
+ @template = template
70
+ end
60
71
  end
61
72
 
62
73
  # return true if this has a description, otherwise false
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DynamicMigrations
4
- VERSION = "3.5.2"
4
+ VERSION = "3.6.0"
5
5
  end
@@ -77,6 +77,8 @@ require "dynamic_migrations/postgres/generator/primary_key"
77
77
  require "dynamic_migrations/postgres/generator/trigger"
78
78
  require "dynamic_migrations/postgres/generator/unique_constraint"
79
79
  require "dynamic_migrations/postgres/generator/validation"
80
+ require "dynamic_migrations/postgres/generator/validation_template_base"
81
+ require "dynamic_migrations/postgres/generator/trigger_template_base"
80
82
  require "dynamic_migrations/postgres/generator"
81
83
  require "dynamic_migrations/postgres/generator/fragment"
82
84
  require "dynamic_migrations/postgres/generator/migration"
@@ -1,5 +1,3 @@
1
- # TypeProf 0.21.7
2
-
3
1
  # Classes
4
2
  module DynamicMigrations
5
3
  module ActiveRecord
@@ -10,6 +8,13 @@ module DynamicMigrations
10
8
  def set_trigger_comment: (Symbol table_name, Symbol trigger_name, String comment) -> void
11
9
  def remove_trigger_comment: (Symbol table_name, Symbol trigger_name) -> void
12
10
 
11
+ def before_insert: (Symbol table_name, name: Symbol, function_schema_name: Symbol, function_name: Symbol, ?parameters: String?, ?action_condition: String?, ?action_reference_old_table: Symbol?, ?action_reference_new_table: Symbol?, ?comment: String?) -> void
12
+ def before_update: (Symbol table_name, name: Symbol, function_schema_name: Symbol, function_name: Symbol, ?parameters: String?, ?action_condition: String?, ?action_reference_old_table: Symbol?, ?action_reference_new_table: Symbol?, ?comment: String?) -> void
13
+ def before_delete: (Symbol table_name, name: Symbol, function_schema_name: Symbol, function_name: Symbol, ?parameters: String?, ?action_condition: String?, ?action_reference_old_table: Symbol?, ?action_reference_new_table: Symbol?, ?comment: String?) -> void
14
+ def after_insert: (Symbol table_name, name: Symbol, function_schema_name: Symbol, function_name: Symbol, ?parameters: String?, ?action_condition: String?, ?action_reference_old_table: Symbol?, ?action_reference_new_table: Symbol?, ?comment: String?) -> void
15
+ def after_update: (Symbol table_name, name: Symbol, function_schema_name: Symbol, function_name: Symbol, ?parameters: String?, ?action_condition: String?, ?action_reference_old_table: Symbol?, ?action_reference_new_table: Symbol?, ?comment: String?) -> void
16
+ def after_delete: (Symbol table_name, name: Symbol, function_schema_name: Symbol, function_name: Symbol, ?parameters: String?, ?action_condition: String?, ?action_reference_old_table: Symbol?, ?action_reference_new_table: Symbol?, ?comment: String?) -> void
17
+
13
18
  # stubbing these out, as they are available on the module which includes this module
14
19
  def execute: (String sql) -> void
15
20
  def schema_name: () -> Symbol
@@ -1,10 +1,14 @@
1
- # TypeProf 0.21.7
2
-
3
1
  # Classes
4
2
  module DynamicMigrations
5
3
  module Postgres
6
4
  class Generator
7
5
  module Trigger
6
+ self.@templates: Hash[Symbol, singleton(TriggerTemplateBase)]
7
+
8
+ def self.template: (Symbol template_name) -> singleton(TriggerTemplateBase)
9
+ def self.has_template?: (Symbol template_name) -> bool
10
+ def self.add_template: (Symbol template_name, singleton(TriggerTemplateBase) template_class) -> void
11
+
8
12
  def add_trigger: (Server::Database::Schema::Table::Trigger trigger, ?String? code_comment) -> Fragment
9
13
  def remove_trigger: (Server::Database::Schema::Table::Trigger trigger, ?String? code_comment) -> Fragment
10
14
  def recreate_trigger: (Server::Database::Schema::Table::Trigger original_trigger, Server::Database::Schema::Table::Trigger updated_trigger) -> Array[Fragment]
@@ -16,6 +20,11 @@ module DynamicMigrations
16
20
 
17
21
  def indent: (String migration, ?Integer levels) -> String
18
22
 
23
+ class UnexpectedTemplateError < StandardError
24
+ end
25
+
26
+ class TemplateAlreadyExistsError < StandardError
27
+ end
19
28
  end
20
29
  end
21
30
  end
@@ -0,0 +1,25 @@
1
+ # Classes
2
+ module DynamicMigrations
3
+ module Postgres
4
+ class Generator
5
+ class TriggerTemplateBase
6
+ @code_comment: untyped
7
+
8
+ attr_reader trigger: untyped
9
+
10
+ def initialize: (untyped trigger, untyped code_comment) -> void
11
+
12
+ # abstract method (should actually be added to child classes)
13
+ def fragment_arguments: -> {schema: Postgres::Server::Database::Schema, table: Postgres::Server::Database::Schema::Table, migration_method: :add_validation, object: Postgres::Server::Database::Schema::Table::Validation, code_comment: String?, migration: String}
14
+
15
+ private
16
+ def assert_column_count!: (?Integer count) -> nil
17
+ def first_column: -> untyped
18
+ def indent: (untyped multi_line_string, ?Integer levels) -> untyped
19
+
20
+ class TemplateError < StandardError
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -5,6 +5,12 @@ module DynamicMigrations
5
5
  module Postgres
6
6
  class Generator
7
7
  module Validation
8
+ self.@templates: Hash[Symbol, singleton(ValidationTemplateBase)]
9
+
10
+ def self.template: (Symbol template_name) -> singleton(ValidationTemplateBase)
11
+ def self.has_template?: (Symbol template_name) -> bool
12
+ def self.add_template: (Symbol template_name, singleton(ValidationTemplateBase) template_class) -> void
13
+
8
14
  def add_validation: (Postgres::Server::Database::Schema::Table::Validation validation, ?String? code_comment) -> Fragment
9
15
  def remove_validation: (Postgres::Server::Database::Schema::Table::Validation validation, ?String? code_comment) -> Fragment
10
16
  def recreate_validation: (Postgres::Server::Database::Schema::Table::Validation original_validation, Postgres::Server::Database::Schema::Table::Validation updated_validation) -> Array[Fragment]
@@ -15,7 +21,13 @@ module DynamicMigrations
15
21
  def add_fragment: (migration_method: Symbol, object: untyped, migration: String, ?schema: Server::Database::Schema?, ?table: Server::Database::Schema::Table?, ?code_comment: String?, ?dependent_table: Server::Database::Schema::Table?) -> untyped
16
22
 
17
23
  def indent: (String migration, ?Integer levels) -> String
24
+
25
+ class UnexpectedTemplateError < StandardError
26
+ end
27
+
28
+ class TemplateAlreadyExistsError < StandardError
18
29
  end
30
+ end
19
31
  end
20
32
  end
21
33
  end
@@ -0,0 +1,30 @@
1
+ # TypeProf 0.21.8
2
+
3
+ # Classes
4
+ module DynamicMigrations
5
+ module Postgres
6
+ class Generator
7
+ class ValidationTemplateBase
8
+ @code_comment: untyped
9
+
10
+ attr_reader validation: untyped
11
+
12
+ def initialize: (untyped validation, untyped code_comment) -> void
13
+
14
+ # abstract method (should actually be added to child classes)
15
+ def fragment_arguments: -> {schema: Postgres::Server::Database::Schema, table: Postgres::Server::Database::Schema::Table, migration_method: :add_validation, object: Postgres::Server::Database::Schema::Table::Validation, code_comment: String?, migration: String}
16
+
17
+ private
18
+ def assert_not_deferred!: -> nil
19
+ def assert_column_count!: (?Integer count) -> nil
20
+ def first_column: -> untyped
21
+ def value_from_check_clause: (untyped regex) -> untyped
22
+ def name_and_description_options_string: (untyped default_name) -> String?
23
+ def indent: (String multi_line_string, ?Integer levels) -> String
24
+
25
+ class TemplateError < StandardError
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -20,8 +20,9 @@ module DynamicMigrations
20
20
  attr_reader action_reference_old_table: Symbol?
21
21
  attr_reader action_reference_new_table: Symbol?
22
22
  attr_reader description: String?
23
+ attr_reader template: Symbol?
23
24
 
24
- def initialize: (database_or_configuration source, Table table, Symbol name, action_timing: Symbol, event_manipulation: Symbol, parameters: String?, action_orientation: Symbol, function: Function, ?action_order: Integer?, ?action_condition: String?, ?action_reference_old_table: Symbol?, ?action_reference_new_table: Symbol?, ?description: String?) -> void
25
+ def initialize: (database_or_configuration source, Table table, Symbol name, action_timing: Symbol, event_manipulation: Symbol, parameters: String?, action_orientation: Symbol, function: Function, ?action_order: Integer?, ?action_condition: String?, ?action_reference_old_table: Symbol?, ?action_reference_new_table: Symbol?, ?description: String?, ?template: Symbol?) -> void
25
26
  def action_order: -> Integer
26
27
  def has_description?: -> false
27
28
  def differences_descriptions: (Trigger other_trigger) -> Array[String]
@@ -52,6 +53,9 @@ module DynamicMigrations
52
53
 
53
54
  class UnexpectedActionOrderError < StandardError
54
55
  end
56
+
57
+ class UnexpectedTemplateError < StandardError
58
+ end
55
59
  end
56
60
  end
57
61
  end
@@ -14,7 +14,7 @@ module DynamicMigrations
14
14
  def has_trigger?: (untyped name) -> bool
15
15
  def triggers: -> Array[Trigger]
16
16
  def triggers_hash: -> Hash[Symbol, Trigger]
17
- def add_trigger: (Symbol name, action_timing: Symbol, event_manipulation: Symbol, parameters: String, action_orientation: Symbol, function: Function, ?action_order: Integer?, ?action_condition: String?, ?action_reference_old_table: Symbol?, ?action_reference_new_table: Symbol?, ?description: String?) -> Trigger
17
+ def add_trigger: (Symbol name, action_timing: Symbol, event_manipulation: Symbol, parameters: String, action_orientation: Symbol, function: Function, ?action_order: Integer?, ?action_condition: String?, ?action_reference_old_table: Symbol?, ?action_reference_new_table: Symbol?, ?description: String?, ?template: Symbol?) -> Trigger
18
18
 
19
19
  # these come from the table object (which this module is included into)
20
20
  def source: -> database_or_configuration
@@ -13,8 +13,9 @@ module DynamicMigrations
13
13
  attr_reader deferrable: bool
14
14
  attr_reader initially_deferred: bool
15
15
  attr_reader description: String?
16
+ attr_reader template: Symbol?
16
17
 
17
- def initialize: (database_or_configuration source, Table table, Array[Column] columns, Symbol name, String check_clause, ?deferrable: bool, ?initially_deferred: bool, ?description: String?) -> void
18
+ def initialize: (database_or_configuration source, Table table, Array[Column] columns, Symbol name, String check_clause, ?deferrable: bool, ?initially_deferred: bool, ?description: String?, ?template: Symbol?) -> void
18
19
  def columns: -> Array[Column]
19
20
  def column_names: -> Array[Symbol]
20
21
  def has_description?: -> bool
@@ -34,6 +35,10 @@ module DynamicMigrations
34
35
 
35
36
  class ModuleIncludedIntoUnexpectedTargetError < StandardError
36
37
  end
38
+
39
+ class UnexpectedTemplateError < StandardError
40
+ end
41
+
37
42
  end
38
43
  end
39
44
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dynamic_migrations
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.5.2
4
+ version: 3.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Craig Ulliott
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-11 00:00:00.000000000 Z
11
+ date: 2023-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg
@@ -102,8 +102,10 @@ files:
102
102
  - lib/dynamic_migrations/postgres/generator/table.rb
103
103
  - lib/dynamic_migrations/postgres/generator/table_migration.rb
104
104
  - lib/dynamic_migrations/postgres/generator/trigger.rb
105
+ - lib/dynamic_migrations/postgres/generator/trigger_template_base.rb
105
106
  - lib/dynamic_migrations/postgres/generator/unique_constraint.rb
106
107
  - lib/dynamic_migrations/postgres/generator/validation.rb
108
+ - lib/dynamic_migrations/postgres/generator/validation_template_base.rb
107
109
  - lib/dynamic_migrations/postgres/server.rb
108
110
  - lib/dynamic_migrations/postgres/server/database.rb
109
111
  - lib/dynamic_migrations/postgres/server/database/configured_extensions.rb
@@ -192,8 +194,10 @@ files:
192
194
  - sig/dynamic_migrations/postgres/generator/table.rbs
193
195
  - sig/dynamic_migrations/postgres/generator/table_migration.rbs
194
196
  - sig/dynamic_migrations/postgres/generator/trigger.rbs
197
+ - sig/dynamic_migrations/postgres/generator/trigger_template_base.rbs
195
198
  - sig/dynamic_migrations/postgres/generator/unique_constraint.rbs
196
199
  - sig/dynamic_migrations/postgres/generator/validation.rbs
200
+ - sig/dynamic_migrations/postgres/generator/validation_template_base.rbs
197
201
  - sig/dynamic_migrations/postgres/server.rbs
198
202
  - sig/dynamic_migrations/postgres/server/database.rbs
199
203
  - sig/dynamic_migrations/postgres/server/database/configured_extensions.rbs