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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e8f9a1a4cf3316579443b0fed7898a42ab410ba114d194c5ffb874a5ca5027d9
4
- data.tar.gz: 03651b7187cef799edee4d64e9c7533f0c6fb9ce0f9193b16e721c13e508373b
3
+ metadata.gz: d3402241c1537169c438a53ccadd5bc53c048479d75164afe5ec7659bc8f65c3
4
+ data.tar.gz: 0dd0e31a82d757ee980b12c51f8baff81cc9a698308be775a2112bc89fa75fc3
5
5
  SHA512:
6
- metadata.gz: cfdbf88d363b8280f18d1aa63cc7ad9d917de7d5c0582ae43a02ac9341af4c00918f6cd5382c935c2a1a1026873afdd98e2aed42397a722b8660fb876133408a
7
- data.tar.gz: 35451e4c7cfbcfa0a7dec0133b726d005c32ff4c1d7d2792737f24b4b7c2da98b0ba50250f30876f99743d16b911201243d0a0252f162794ec6a08e1955cc634
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
- $$BEGIN #{fn_sql}
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
- $$BEGIN #{fn_sql}
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
- multi_line_string.gsub("\n", "\n ")
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
@@ -198,7 +198,7 @@ module DynamicMigrations
198
198
  :event_manipulation,
199
199
  :action_order,
200
200
  :action_condition,
201
- :action_statement,
201
+ :parameters,
202
202
  :action_orientation,
203
203
  :action_reference_old_table,
204
204
  :action_reference_new_table,
@@ -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
- action_statement: trigger_definition[:action_statement],
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 UnexpectedActionOrderError < StandardError
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 :action_statement
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:, action_order:, action_statement:, action_orientation:, function:, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, description: nil
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
- unless action_order.is_a?(Integer) && action_order >= 1
76
- raise UnexpectedActionOrderError, action_order
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 action_statement.is_a?(String) && action_statement[/\AEXECUTE FUNCTION [a-z]+(_[a-z]+)*\.[a-z]+(_[a-z]+)*\(\)\z/]
86
- raise UnexpectedActionStatementError, "unexpected action statement `#{action_statement}`, currently only `EXECUTE FUNCTION function_name()` statements are supported"
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
- @action_statement = action_statement
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
- :action_statement,
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:, action_order:, action_statement:, action_orientation:, function:, 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
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, action_statement: action_statement, 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
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
- POSITION(
45
- ('EXECUTE FUNCTION') IN (
46
- SUBSTRING(
47
- pg_get_triggerdef(t.oid)
48
- FROM
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
- action_statement: row["action_statement"],
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DynamicMigrations
4
- VERSION = "3.2.2"
4
+ VERSION = "3.3.0"
5
5
  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.2.2
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-17 00:00:00.000000000 Z
11
+ date: 2023-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg