dynamic_migrations 3.5.3 → 3.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8db557bd15584279e5453bf8e11664fbc5c9cbce80da60feaede298aa2931450
4
- data.tar.gz: 52c990e7611103a9bc60daa33d673f7f9d62cf753253419d3a237c44394eeecf
3
+ metadata.gz: a25d76d54d7129a77f16574c4b6a84cf82ca6105afe4279ba868b34b97fa4814
4
+ data.tar.gz: b60f87c21dd0e53aed9853d4eaece239cab1d2524ba9c500e3dc364eda1d40dd
5
5
  SHA512:
6
- metadata.gz: 5ba74991b8200a6b0725b77e6db992783f994ebebf6c362b92077757f11a0a5bd48cbf1b6a88c324caa23b461011a2248bfeafbb833610f7d82ad9a5e8d74291
7
- data.tar.gz: 10ac70b56fe1a6c5ddd429321ee88b8134f3c1d20e9fe5ef70460f75117d73374a2d79893169b12289c755295491e99dc627f8ec851498a387cd6fe3812f0fdc
6
+ metadata.gz: ef75931965eb2dd877bd22a82b4ad6532df5ab4e9e5ff24cc160f9fcc81c3c1db7eca2698b30da99a29000c7c67cf4efd1f5d7eca8ff28fbcc31631a0d43225b
7
+ data.tar.gz: 4d4218e2872b79b68b79517696403f3aa15c1b87ac2c9b8afd47e1ebb4a1fcb1b3e3efbd0f0db61ad788e8c80472b2eef1d389e08dbf0153414dcfecab5b976c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
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
+
3
15
  ## [3.5.3](https://github.com/craigulliott/dynamic_migrations/compare/v3.5.2...v3.5.3) (2023-09-11)
4
16
 
5
17
 
@@ -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
@@ -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.3"
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.3
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