dynamic_migrations 3.2.2 → 3.3.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 +4 -4
- data/CHANGELOG.md +14 -0
- data/lib/dynamic_migrations/active_record/migrators/function.rb +2 -16
- data/lib/dynamic_migrations/active_record/migrators/trigger.rb +2 -2
- data/lib/dynamic_migrations/postgres/generator/function.rb +2 -10
- data/lib/dynamic_migrations/postgres/generator/trigger.rb +4 -0
- data/lib/dynamic_migrations/postgres/generator.rb +3 -2
- data/lib/dynamic_migrations/postgres/server/database/differences.rb +1 -1
- data/lib/dynamic_migrations/postgres/server/database/loaded_schemas_builder.rb +1 -1
- data/lib/dynamic_migrations/postgres/server/database/schema/function.rb +3 -3
- data/lib/dynamic_migrations/postgres/server/database/schema/table/trigger.rb +56 -14
- data/lib/dynamic_migrations/postgres/server/database/schema/table/triggers.rb +2 -2
- data/lib/dynamic_migrations/postgres/server/database/triggers_and_functions_loader.rb +6 -14
- data/lib/dynamic_migrations/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3402241c1537169c438a53ccadd5bc53c048479d75164afe5ec7659bc8f65c3
|
4
|
+
data.tar.gz: 0dd0e31a82d757ee980b12c51f8baff81cc9a698308be775a2112bc89fa75fc3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27fd59935f7d85a81fde4ce74899490917396d8598be9f3a23c8fb5b59a49f9049c85a703ec50d3e9b4040db6ce0acb72ecfa579eb2304bf7d8a79a17ebbccda
|
7
|
+
data.tar.gz: 043f54479dfbe7078755a4a258f7ff8a7d0d6fc12208e6849f5a452b473fc28fd0f04c612b9af959f0c69d1b230107a90409b122dcf0e92f33cc32ea1067f716
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [3.3.0](https://github.com/craigulliott/dynamic_migrations/compare/v3.2.2...v3.3.0) (2023-08-18)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* adding parameters to triggers ([0d48466](https://github.com/craigulliott/dynamic_migrations/commit/0d484664dd344c34804580fb939a2807339a0552))
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* only accepting action_order for loaded triggers, and calculating its value dynamically for configured triggers ([0d48466](https://github.com/craigulliott/dynamic_migrations/commit/0d484664dd344c34804580fb939a2807339a0552))
|
14
|
+
* providing full function definition within specs (to conform with updated pg_spec_helper gem) ([0d48466](https://github.com/craigulliott/dynamic_migrations/commit/0d484664dd344c34804580fb939a2807339a0552))
|
15
|
+
* removing unused action_statement from triggers ([0d48466](https://github.com/craigulliott/dynamic_migrations/commit/0d484664dd344c34804580fb939a2807339a0552))
|
16
|
+
|
3
17
|
## [3.2.2](https://github.com/craigulliott/dynamic_migrations/compare/v3.2.1...v3.2.2) (2023-08-17)
|
4
18
|
|
5
19
|
|
@@ -18,17 +18,10 @@ module DynamicMigrations
|
|
18
18
|
fn_sql = block.call.strip
|
19
19
|
end
|
20
20
|
|
21
|
-
# ensure that the function ends with a semicolon
|
22
|
-
unless fn_sql.end_with? ";"
|
23
|
-
fn_sql << ";"
|
24
|
-
end
|
25
|
-
|
26
21
|
# schema_name was not provided to this method, it comes from the migration class
|
27
22
|
execute <<~SQL
|
28
23
|
CREATE FUNCTION #{schema_name}.#{function_name}() returns trigger language plpgsql AS
|
29
|
-
|
30
|
-
RETURN NEW;
|
31
|
-
END$$;
|
24
|
+
$$#{fn_sql}$$;
|
32
25
|
SQL
|
33
26
|
|
34
27
|
if comment.is_a? String
|
@@ -46,11 +39,6 @@ module DynamicMigrations
|
|
46
39
|
fn_sql = block.call.strip
|
47
40
|
end
|
48
41
|
|
49
|
-
# ensure that the function ends with a semicolon
|
50
|
-
unless fn_sql.end_with? ";"
|
51
|
-
fn_sql << ";"
|
52
|
-
end
|
53
|
-
|
54
42
|
# schema_name was not provided to this method, it comes from the migration class
|
55
43
|
# assert it already exists
|
56
44
|
exists_result = execute <<~SQL
|
@@ -72,9 +60,7 @@ module DynamicMigrations
|
|
72
60
|
# create or replace will update the function
|
73
61
|
execute <<~SQL
|
74
62
|
CREATE OR REPLACE FUNCTION #{schema_name}.#{function_name}() returns trigger language plpgsql AS
|
75
|
-
|
76
|
-
RETURN NEW;
|
77
|
-
END$$;
|
63
|
+
$$#{fn_sql}$$;
|
78
64
|
SQL
|
79
65
|
|
80
66
|
if comment.is_a? String
|
@@ -16,7 +16,7 @@ module DynamicMigrations
|
|
16
16
|
end
|
17
17
|
|
18
18
|
# create a postgres trigger
|
19
|
-
def add_trigger table_name, name:, action_timing:, event_manipulation:, action_orientation:, function_schema_name:, function_name:, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, comment: nil
|
19
|
+
def add_trigger table_name, name:, action_timing:, event_manipulation:, action_orientation:, function_schema_name:, function_name:, parameters: nil, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, comment: nil
|
20
20
|
unless [:insert, :delete, :update].include? event_manipulation
|
21
21
|
raise UnexpectedEventManipulationError, event_manipulation
|
22
22
|
end
|
@@ -53,7 +53,7 @@ module DynamicMigrations
|
|
53
53
|
#{timing_sql} ON #{schema_name}.#{table_name} #{temp_tables_sql}
|
54
54
|
FOR EACH #{action_orientation}
|
55
55
|
#{condition_sql}
|
56
|
-
EXECUTE FUNCTION #{function_schema_name}.#{function_name}();
|
56
|
+
EXECUTE FUNCTION #{function_schema_name}.#{function_name}(#{parameters});
|
57
57
|
SQL
|
58
58
|
|
59
59
|
if comment.is_a? String
|
@@ -20,10 +20,6 @@ module DynamicMigrations
|
|
20
20
|
optional_options_syntax = (options_syntax == "") ? "" : ", #{options_syntax}"
|
21
21
|
|
22
22
|
fn_sql = function.definition.strip
|
23
|
-
# ensure that the function ends with a semicolon
|
24
|
-
unless fn_sql.end_with? ";"
|
25
|
-
fn_sql << ";"
|
26
|
-
end
|
27
23
|
|
28
24
|
add_fragment schema: function.schema,
|
29
25
|
table: function.triggers.first&.table,
|
@@ -33,7 +29,7 @@ module DynamicMigrations
|
|
33
29
|
migration: comment_sql + <<~RUBY
|
34
30
|
create_function :#{function.name}#{optional_options_syntax} do
|
35
31
|
<<~SQL
|
36
|
-
#{indent fn_sql}
|
32
|
+
#{indent fn_sql, 2}
|
37
33
|
SQL
|
38
34
|
end
|
39
35
|
RUBY
|
@@ -41,10 +37,6 @@ module DynamicMigrations
|
|
41
37
|
|
42
38
|
def update_function function, code_comment = nil
|
43
39
|
fn_sql = function.definition.strip
|
44
|
-
# ensure that the function ends with a semicolon
|
45
|
-
unless fn_sql.end_with? ";"
|
46
|
-
fn_sql << ";"
|
47
|
-
end
|
48
40
|
|
49
41
|
add_fragment schema: function.schema,
|
50
42
|
table: function.triggers.first&.table,
|
@@ -54,7 +46,7 @@ module DynamicMigrations
|
|
54
46
|
migration: <<~RUBY
|
55
47
|
update_function :#{function.name} do
|
56
48
|
<<~SQL
|
57
|
-
#{indent fn_sql}
|
49
|
+
#{indent fn_sql, 2}
|
58
50
|
SQL
|
59
51
|
end
|
60
52
|
RUBY
|
@@ -28,6 +28,10 @@ module DynamicMigrations
|
|
28
28
|
options[:action_condition] = ":#{trigger.action_condition}"
|
29
29
|
end
|
30
30
|
|
31
|
+
unless trigger.parameters.nil?
|
32
|
+
options[:parameters] = "\"#{trigger.parameters}\""
|
33
|
+
end
|
34
|
+
|
31
35
|
unless trigger.action_reference_old_table.nil?
|
32
36
|
options[:action_reference_old_table] = ":#{trigger.action_reference_old_table}"
|
33
37
|
end
|
@@ -216,8 +216,9 @@ module DynamicMigrations
|
|
216
216
|
fragment
|
217
217
|
end
|
218
218
|
|
219
|
-
def indent multi_line_string
|
220
|
-
|
219
|
+
def indent multi_line_string, levels = 1
|
220
|
+
spaces = " " * levels
|
221
|
+
multi_line_string.gsub("\n", "\n#{spaces}")
|
221
222
|
end
|
222
223
|
|
223
224
|
def strip_empty_lines multi_line_string
|
@@ -92,7 +92,7 @@ module DynamicMigrations
|
|
92
92
|
table.add_trigger trigger_name, action_timing: trigger_definition[:action_timing],
|
93
93
|
event_manipulation: trigger_definition[:event_manipulation],
|
94
94
|
action_order: trigger_definition[:action_order],
|
95
|
-
|
95
|
+
parameters: trigger_definition[:parameters],
|
96
96
|
action_orientation: trigger_definition[:action_orientation],
|
97
97
|
function: function,
|
98
98
|
action_condition: trigger_definition[:action_condition],
|
@@ -31,10 +31,10 @@ module DynamicMigrations
|
|
31
31
|
raise ExpectedSymbolError, name unless name.is_a? Symbol
|
32
32
|
@name = name
|
33
33
|
|
34
|
-
unless definition.is_a?(String) && definition.strip != ""
|
35
|
-
raise ExpectedDefinitionError, definition
|
34
|
+
unless definition.is_a?(String) && definition.strip != "" && definition.strip.end_with?("END;")
|
35
|
+
raise ExpectedDefinitionError, "Definition must be a string, and end with `END;`. Definition provided:\n#{definition}"
|
36
36
|
end
|
37
|
-
@definition = definition
|
37
|
+
@definition = definition.strip
|
38
38
|
|
39
39
|
unless description.nil?
|
40
40
|
raise ExpectedStringError, description unless description.is_a? String
|
@@ -14,10 +14,7 @@ module DynamicMigrations
|
|
14
14
|
class UnexpectedEventManipulationError < StandardError
|
15
15
|
end
|
16
16
|
|
17
|
-
class
|
18
|
-
end
|
19
|
-
|
20
|
-
class UnexpectedActionStatementError < StandardError
|
17
|
+
class UnexpectedParametersError < StandardError
|
21
18
|
end
|
22
19
|
|
23
20
|
class UnexpectedActionOrientationError < StandardError
|
@@ -35,13 +32,15 @@ module DynamicMigrations
|
|
35
32
|
class ExpectedFunctionError < StandardError
|
36
33
|
end
|
37
34
|
|
35
|
+
class UnexpectedActionOrderError < StandardError
|
36
|
+
end
|
37
|
+
|
38
38
|
attr_reader :table
|
39
39
|
attr_reader :name
|
40
40
|
attr_reader :event_manipulation
|
41
41
|
attr_reader :action_timing
|
42
|
-
attr_reader :action_order
|
43
42
|
attr_reader :action_condition
|
44
|
-
attr_reader :
|
43
|
+
attr_reader :parameters
|
45
44
|
attr_reader :action_orientation
|
46
45
|
attr_reader :function
|
47
46
|
attr_reader :action_reference_old_table
|
@@ -49,7 +48,7 @@ module DynamicMigrations
|
|
49
48
|
attr_reader :description
|
50
49
|
|
51
50
|
# initialize a new object to represent a validation in a postgres table
|
52
|
-
def initialize source, table, name, action_timing:, event_manipulation:,
|
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
|
53
52
|
super source
|
54
53
|
|
55
54
|
unless table.is_a? Table
|
@@ -72,20 +71,27 @@ module DynamicMigrations
|
|
72
71
|
end
|
73
72
|
@event_manipulation = event_manipulation
|
74
73
|
|
75
|
-
|
76
|
-
|
74
|
+
if from_configuration?
|
75
|
+
unless action_order.nil?
|
76
|
+
raise UnexpectedActionOrderError, "Unexpected `action_order` argument. Action order is calculated dynamically for configured triggers."
|
77
|
+
end
|
78
|
+
|
79
|
+
else
|
80
|
+
unless action_order.is_a?(Integer) && action_order >= 1
|
81
|
+
raise UnexpectedActionOrderError, "Missing valid `action_order` argument. Action order must be provided for triggers loaded from the database."
|
82
|
+
end
|
83
|
+
@action_order = action_order
|
77
84
|
end
|
78
|
-
@action_order = action_order
|
79
85
|
|
80
86
|
unless action_condition.nil? || action_condition.is_a?(String)
|
81
87
|
raise ExpectedStringError, action_condition
|
82
88
|
end
|
83
89
|
@action_condition = action_condition
|
84
90
|
|
85
|
-
unless
|
86
|
-
raise
|
91
|
+
unless parameters.nil? || (parameters.is_a?(String) && parameters[/\A'[\w\d_ -]+'(, ?'[\w\d_ -]+')*\z/])
|
92
|
+
raise UnexpectedParametersError, "unexpected parameters `#{parameters}`, currently only a comma seeparated list of strings is supported"
|
87
93
|
end
|
88
|
-
@
|
94
|
+
@parameters = parameters
|
89
95
|
|
90
96
|
unless [:row, :statement].include? action_orientation
|
91
97
|
raise UnexpectedActionOrientationError, action_orientation
|
@@ -120,6 +126,42 @@ module DynamicMigrations
|
|
120
126
|
end
|
121
127
|
end
|
122
128
|
|
129
|
+
def action_order
|
130
|
+
# if the source is the database, then return the locally stored
|
131
|
+
# representation of the action order
|
132
|
+
if from_database?
|
133
|
+
action_order = @action_order
|
134
|
+
if action_order.nil?
|
135
|
+
raise "Missing valid action_order. This should be impossible."
|
136
|
+
end
|
137
|
+
action_order
|
138
|
+
|
139
|
+
# otherwise return the dynamically calculated action order, this is calculated
|
140
|
+
# by returning this triggers index in the list of alphabetically sorted triggers
|
141
|
+
# for this triggers table
|
142
|
+
else
|
143
|
+
pos = @table.triggers.sort_by(&:name).index(self)
|
144
|
+
if pos.nil?
|
145
|
+
raise "Trigger not found in table triggers list. This should be impossible."
|
146
|
+
end
|
147
|
+
pos + 1
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def action_condition= new_action_condition
|
152
|
+
unless new_action_condition.nil? || new_action_condition.is_a?(String)
|
153
|
+
raise ExpectedStringError, new_action_condition
|
154
|
+
end
|
155
|
+
@action_condition = new_action_condition
|
156
|
+
end
|
157
|
+
|
158
|
+
def parameters= new_parameters
|
159
|
+
unless new_parameters.nil? || new_parameters.is_a?(String)
|
160
|
+
raise ExpectedStringError, new_parameters
|
161
|
+
end
|
162
|
+
@parameters = new_parameters
|
163
|
+
end
|
164
|
+
|
123
165
|
# return true if this has a description, otherwise false
|
124
166
|
def has_description?
|
125
167
|
!@description.nil?
|
@@ -131,7 +173,7 @@ module DynamicMigrations
|
|
131
173
|
:action_timing,
|
132
174
|
:action_order,
|
133
175
|
:action_condition,
|
134
|
-
:
|
176
|
+
:parameters,
|
135
177
|
:action_orientation,
|
136
178
|
:action_reference_old_table,
|
137
179
|
:action_reference_new_table
|
@@ -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:,
|
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
|
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,
|
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
|
48
48
|
else
|
49
49
|
raise ModuleIncludedIntoUnexpectedTargetError, included_target
|
50
50
|
end
|
@@ -35,22 +35,14 @@ module DynamicMigrations
|
|
35
35
|
'.{35,} WHEN ((.+)) EXECUTE FUNCTION'
|
36
36
|
)
|
37
37
|
) [1] ELSE NULL END AS action_condition,
|
38
|
-
p_n.nspname AS function_schema,
|
39
|
-
p.proname AS function_name,
|
40
|
-
p.prosrc AS function_definition,
|
41
38
|
SUBSTRING(
|
42
39
|
pg_get_triggerdef(t.oid)
|
43
40
|
FROM
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
48
|
50
|
-
)
|
51
|
-
)
|
52
|
-
) + 47
|
53
|
-
) AS action_statement,
|
41
|
+
'\\(([\d\w_''-]+)\\)$'
|
42
|
+
) AS parameters,
|
43
|
+
p_n.nspname AS function_schema,
|
44
|
+
p.proname AS function_name,
|
45
|
+
p.prosrc AS function_definition,
|
54
46
|
CASE t.tgtype & 1 WHEN 1 THEN 'row' ELSE 'statement' END AS action_orientation,
|
55
47
|
CASE t.tgtype & 66 WHEN 2 THEN 'before' WHEN 64 THEN 'instead_of' ELSE 'after' END AS action_timing,
|
56
48
|
t.tgoldtable AS action_reference_old_table,
|
@@ -112,7 +104,7 @@ module DynamicMigrations
|
|
112
104
|
function_schema: row["function_schema"].to_sym,
|
113
105
|
function_name: row["function_name"].to_sym,
|
114
106
|
function_definition: row["function_definition"],
|
115
|
-
|
107
|
+
parameters: row["parameters"],
|
116
108
|
action_orientation: row["action_orientation"].to_sym,
|
117
109
|
action_timing: row["action_timing"].to_sym,
|
118
110
|
# `action_reference_old_table` and `action_reference_new_table` can be null
|
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.3.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-08-
|
11
|
+
date: 2023-08-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|