dynamic_migrations 3.5.3 → 3.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/lib/dynamic_migrations/active_record/migrators/trigger.rb +12 -12
- data/lib/dynamic_migrations/postgres/generator/trigger.rb +83 -49
- data/lib/dynamic_migrations/postgres/generator/trigger_template_base.rb +38 -0
- data/lib/dynamic_migrations/postgres/generator/validation.rb +68 -33
- data/lib/dynamic_migrations/postgres/generator/validation_template_base.rb +74 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/trigger.rb +12 -1
- data/lib/dynamic_migrations/postgres/server/database/schema/table/triggers.rb +2 -2
- data/lib/dynamic_migrations/postgres/server/database/schema/table/validation.rb +12 -1
- data/lib/dynamic_migrations/version.rb +1 -1
- data/lib/dynamic_migrations.rb +2 -0
- data/sig/dynamic_migrations/active_record/migrators/trigger.rbs +7 -2
- data/sig/dynamic_migrations/postgres/generator/trigger.rbs +11 -2
- data/sig/dynamic_migrations/postgres/generator/trigger_template_base.rbs +25 -0
- data/sig/dynamic_migrations/postgres/generator/validation.rbs +12 -0
- data/sig/dynamic_migrations/postgres/generator/validation_template_base.rbs +30 -0
- data/sig/dynamic_migrations/postgres/server/database/schema/table/trigger.rbs +5 -1
- data/sig/dynamic_migrations/postgres/server/database/schema/table/triggers.rbs +1 -1
- data/sig/dynamic_migrations/postgres/server/database/schema/table/validation.rbs +6 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a25d76d54d7129a77f16574c4b6a84cf82ca6105afe4279ba868b34b97fa4814
|
4
|
+
data.tar.gz: b60f87c21dd0e53aed9853d4eaece239cab1d2524ba9c500e3dc364eda1d40dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
6
|
-
|
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
|
-
|
28
|
-
|
29
|
-
end
|
8
|
+
class TemplateAlreadyExistsError < StandardError
|
9
|
+
end
|
30
10
|
|
31
|
-
|
32
|
-
|
33
|
-
|
11
|
+
def self.template template_name
|
12
|
+
@templates && @templates[template_name]
|
13
|
+
end
|
34
14
|
|
35
|
-
|
36
|
-
|
37
|
-
|
15
|
+
def self.has_template? template_name
|
16
|
+
@templates&.key?(template_name) || false
|
17
|
+
end
|
38
18
|
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
34
|
+
arguments = template_class.new(trigger, code_comment).fragment_arguments
|
35
|
+
add_fragment(**arguments)
|
52
36
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
40
|
+
options = {
|
41
|
+
name: ":#{validation.name}",
|
42
|
+
deferrable: validation.deferrable,
|
43
|
+
initially_deferred: validation.initially_deferred
|
44
|
+
}
|
24
45
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
data/lib/dynamic_migrations.rb
CHANGED
@@ -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.
|
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
|
+
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
|