dynamic_migrations 3.2.2 → 3.3.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 +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
|