dynamic_migrations 3.5.3 → 3.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8db557bd15584279e5453bf8e11664fbc5c9cbce80da60feaede298aa2931450
4
- data.tar.gz: 52c990e7611103a9bc60daa33d673f7f9d62cf753253419d3a237c44394eeecf
3
+ metadata.gz: a5f6a69d0ef49c88c5d4f7d1f3798e6a4272fccdad5e3e1c2f5887cf43e552a9
4
+ data.tar.gz: c3faf73058b222ac2a7b10006022d8a08e8b311efad48481f3b64e204b0b3c33
5
5
  SHA512:
6
- metadata.gz: 5ba74991b8200a6b0725b77e6db992783f994ebebf6c362b92077757f11a0a5bd48cbf1b6a88c324caa23b461011a2248bfeafbb833610f7d82ad9a5e8d74291
7
- data.tar.gz: 10ac70b56fe1a6c5ddd429321ee88b8134f3c1d20e9fe5ef70460f75117d73374a2d79893169b12289c755295491e99dc627f8ec851498a387cd6fe3812f0fdc
6
+ metadata.gz: 1be6d466691eaf92f8b999de32a400cb1e14067618cb9ffe429275110675a516aa2797bc3368ce1d0a4aa66d4021044555cc2e54cb31d1a7290f89b72ae93ce4
7
+ data.tar.gz: 851125f34e2df74a7457d620372321a011459777a30543775eebdda6fcaf7c0cfe5b66e41b1c118bf4d6a029c4f99c8f99150032fa03fc97c18fa3656cd84c54
data/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.6.1](https://github.com/craigulliott/dynamic_migrations/compare/v3.6.0...v3.6.1) (2023-09-13)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * adding attr_reader for :code_comment to provide easier access within migration templates ([b805e24](https://github.com/craigulliott/dynamic_migrations/commit/b805e247ef42ea4dd62973be07057d6e110876a3))
9
+
10
+ ## [3.6.0](https://github.com/craigulliott/dynamic_migrations/compare/v3.5.3...v3.6.0) (2023-09-13)
11
+
12
+
13
+ ### Features
14
+
15
+ * plugin architecture for validation and trigger templates (allows for creating cleaner migrations with custom methods) ([f4e9d5e](https://github.com/craigulliott/dynamic_migrations/commit/f4e9d5eae803196e727a5b4d7314e773cd90ba00))
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * fixed badly generated trigger migration ([f4e9d5e](https://github.com/craigulliott/dynamic_migrations/commit/f4e9d5eae803196e727a5b4d7314e773cd90ba00))
21
+
3
22
  ## [3.5.3](https://github.com/craigulliott/dynamic_migrations/compare/v3.5.2...v3.5.3) (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,39 @@
1
+ module DynamicMigrations
2
+ module Postgres
3
+ class Generator
4
+ class TriggerTemplateBase
5
+ class TemplateError < StandardError
6
+ end
7
+
8
+ attr_reader :trigger
9
+ attr_reader :code_comment
10
+
11
+ def initialize trigger, code_comment
12
+ @trigger = trigger
13
+ @code_comment = code_comment
14
+ end
15
+
16
+ private
17
+
18
+ def assert_column_count! count = 1
19
+ if @trigger.columns.count != count
20
+ raise TemplateError, "#{self.class.name} trigger template requires a trigger with only #{count} column"
21
+ end
22
+ end
23
+
24
+ def first_column
25
+ column = @trigger.columns.first
26
+ if column.nil?
27
+ raise TemplateError, "#{self.class.name} trigger template requires a first column"
28
+ end
29
+ column
30
+ end
31
+
32
+ def indent multi_line_string, levels = 1
33
+ spaces = " " * levels
34
+ multi_line_string.gsub("\n", "\n#{spaces}")
35
+ end
36
+ end
37
+ end
38
+ end
39
+ 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,75 @@
1
+ module DynamicMigrations
2
+ module Postgres
3
+ class Generator
4
+ class ValidationTemplateBase
5
+ class TemplateError < StandardError
6
+ end
7
+
8
+ attr_reader :validation
9
+ attr_reader :code_comment
10
+
11
+ def initialize validation, code_comment
12
+ @validation = validation
13
+ @code_comment = code_comment
14
+ end
15
+
16
+ private
17
+
18
+ def assert_not_deferred!
19
+ if @validation.initially_deferred || @validation.deferrable
20
+ raise TemplateError, "#{self.class.name} validation template requires constraints to be are not deferrable"
21
+ end
22
+ end
23
+
24
+ def assert_column_count! count = 1
25
+ if @validation.columns.count != count
26
+ raise TemplateError, "#{self.class.name} validation template requires a validation with only #{count} column"
27
+ end
28
+ end
29
+
30
+ def first_column
31
+ column = @validation.columns.first
32
+ if column.nil?
33
+ raise TemplateError, "#{self.class.name} validation template requires a first column"
34
+ end
35
+ column
36
+ end
37
+
38
+ def value_from_check_clause regex
39
+ matches = @validation.check_clause.strip.match(regex)
40
+ unless matches
41
+ raise TemplateError, "#{self.class.name} validation template check_clause was not an expected format"
42
+ end
43
+ if matches[:value].nil?
44
+ raise TemplateError, "#{self.class.name} validation template check_clause could not parse out value from regex (expected `value` named capture group in the regex)"
45
+ end
46
+ matches[:value]
47
+ end
48
+
49
+ def name_and_description_options_string default_name
50
+ options = {}
51
+ # we only need to provide a name if it is different than the default
52
+ unless @validation.name == default_name
53
+ options[:name] = @validation.name
54
+ end
55
+ # only provide a comment if it is not nil
56
+ unless @validation.description.nil?
57
+ options[:comment] = <<~RUBY
58
+ <<~COMMENT
59
+ #{indent @validation.description || ""}
60
+ COMMENT
61
+ RUBY
62
+ end
63
+
64
+ options_string = options.map { |k, v| "#{k}: #{v}" }.join(", ")
65
+ options_string.empty? ? nil : ", #{options_string}"
66
+ end
67
+
68
+ def indent multi_line_string, levels = 1
69
+ spaces = " " * levels
70
+ multi_line_string.gsub("\n", "\n#{spaces}")
71
+ end
72
+ end
73
+ end
74
+ end
75
+ 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.1"
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
+
7
+ attr_reader trigger: untyped
8
+ attr_reader code_comment: String?
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
+
9
+ attr_reader validation: untyped
10
+ attr_reader code_comment: String?
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.1
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