dynamic_migrations 3.6.15 → 3.7.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 +37 -0
- data/lib/dynamic_migrations/active_record/migrators/primary_key.rb +21 -0
- data/lib/dynamic_migrations/active_record/migrators.rb +1 -0
- data/lib/dynamic_migrations/postgres/generator/primary_key.rb +32 -0
- data/lib/dynamic_migrations/postgres/generator/table.rb +20 -4
- data/lib/dynamic_migrations/postgres/generator/table_migration.rb +1 -1
- data/lib/dynamic_migrations/postgres/generator/validation.rb +0 -4
- data/lib/dynamic_migrations/postgres/generator/validation_template_base.rb +5 -3
- data/lib/dynamic_migrations/postgres/generator.rb +4 -5
- data/lib/dynamic_migrations/postgres/server/database/connection.rb +3 -1
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/functions.rb +1 -1
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/foreign_key_constraints.rb +2 -2
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/indexes.rb +2 -2
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/triggers.rb +2 -2
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/unique_constraints.rb +2 -2
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/validations.rb +2 -2
- data/lib/dynamic_migrations/postgres/server/database/differences.rb +3 -3
- data/lib/dynamic_migrations/postgres/server/database/enums_loader.rb +1 -1
- data/lib/dynamic_migrations/postgres/server/database/keys_and_unique_constraints_loader.rb +8 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/function.rb +51 -2
- data/lib/dynamic_migrations/postgres/server/database/schema/table/column.rb +29 -2
- data/lib/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraint.rb +4 -7
- data/lib/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraints.rb +5 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/trigger.rb +72 -6
- data/lib/dynamic_migrations/postgres/server/database/schema/table/validation.rb +95 -12
- data/lib/dynamic_migrations/postgres/server/database/schema/table/validations.rb +1 -1
- data/lib/dynamic_migrations/postgres/server/database/schema/table.rb +2 -0
- data/lib/dynamic_migrations/postgres/server/database/structure_loader.rb +9 -1
- data/lib/dynamic_migrations/postgres/server/database/triggers_and_functions_loader.rb +4 -3
- data/lib/dynamic_migrations/postgres/server/database/validations_loader.rb +42 -29
- data/lib/dynamic_migrations/postgres/server/database.rb +6 -0
- data/lib/dynamic_migrations/version.rb +1 -1
- data/lib/dynamic_migrations.rb +1 -0
- data/sig/dynamic_migrations/active_record/migrators/primary_key.rbs +18 -0
- data/sig/dynamic_migrations/postgres/generator/primary_key.rbs +2 -0
- data/sig/dynamic_migrations/postgres/generator/table.rbs +2 -0
- data/sig/dynamic_migrations/postgres/generator/validation_template_base.rbs +7 -7
- data/sig/dynamic_migrations/postgres/generator.rbs +1 -1
- data/sig/dynamic_migrations/postgres/server/database/connection.rbs +1 -1
- data/sig/dynamic_migrations/postgres/server/database/keys_and_unique_constraints_loader.rbs +1 -0
- data/sig/dynamic_migrations/postgres/server/database/schema/enum.rbs +2 -2
- data/sig/dynamic_migrations/postgres/server/database/schema/enums.rbs +1 -1
- data/sig/dynamic_migrations/postgres/server/database/schema/function.rbs +9 -0
- data/sig/dynamic_migrations/postgres/server/database/schema/table/column.rbs +4 -0
- data/sig/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraint.rbs +0 -3
- data/sig/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraints.rbs +1 -0
- data/sig/dynamic_migrations/postgres/server/database/schema/table/trigger.rbs +9 -0
- data/sig/dynamic_migrations/postgres/server/database/schema/table/validation.rbs +9 -1
- data/sig/dynamic_migrations/postgres/server/database/schema/table/validations.rbs +1 -1
- data/sig/dynamic_migrations/postgres/server/database/schema/table.rbs +1 -0
- data/sig/dynamic_migrations/postgres/server/database/structure_loader.rbs +1 -0
- data/sig/dynamic_migrations/postgres/server/database/validations_loader.rbs +1 -0
- data/sig/dynamic_migrations/postgres/server/database.rbs +1 -0
- metadata +4 -2
@@ -38,6 +38,9 @@ module DynamicMigrations
|
|
38
38
|
class UnexpectedTemplateError < StandardError
|
39
39
|
end
|
40
40
|
|
41
|
+
class UnnormalizableActionConditionError < StandardError
|
42
|
+
end
|
43
|
+
|
41
44
|
attr_reader :table
|
42
45
|
attr_reader :name
|
43
46
|
attr_reader :event_manipulation
|
@@ -51,7 +54,7 @@ module DynamicMigrations
|
|
51
54
|
attr_reader :description
|
52
55
|
attr_reader :template
|
53
56
|
|
54
|
-
# initialize a new object to represent a
|
57
|
+
# initialize a new object to represent a trigger in a postgres table
|
55
58
|
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
|
56
59
|
super source
|
57
60
|
|
@@ -147,11 +150,11 @@ module DynamicMigrations
|
|
147
150
|
end
|
148
151
|
action_order
|
149
152
|
|
150
|
-
# otherwise
|
151
|
-
#
|
152
|
-
# for this triggers table
|
153
|
+
# otherwise is is computed by finding the index of the trigger within a list of
|
154
|
+
# triggers that are alphabetically sorted, all of which pertain to the same event
|
155
|
+
# manipulation (such as update, insert, etc.) for this triggers table
|
153
156
|
else
|
154
|
-
pos = @table.triggers.sort_by(&:name).index(self)
|
157
|
+
pos = @table.triggers.select { |t| t.event_manipulation == event_manipulation }.sort_by(&:name).index(self)
|
155
158
|
if pos.nil?
|
156
159
|
raise "Trigger not found in table triggers list. This should be impossible."
|
157
160
|
end
|
@@ -184,7 +187,7 @@ module DynamicMigrations
|
|
184
187
|
:event_manipulation,
|
185
188
|
:action_timing,
|
186
189
|
:action_order,
|
187
|
-
:
|
190
|
+
:normalized_action_condition,
|
188
191
|
:parameters,
|
189
192
|
:action_orientation,
|
190
193
|
:action_reference_old_table,
|
@@ -197,6 +200,69 @@ module DynamicMigrations
|
|
197
200
|
# return the combined differences
|
198
201
|
descriptions
|
199
202
|
end
|
203
|
+
|
204
|
+
# create a temporary table in postgres to represent this trigger and fetch
|
205
|
+
# the actual normalized check constraint directly from the database
|
206
|
+
def normalized_action_condition
|
207
|
+
if action_condition.nil?
|
208
|
+
nil
|
209
|
+
# no need to normalize action_conditions which originated from the database
|
210
|
+
elsif from_database?
|
211
|
+
action_condition
|
212
|
+
else
|
213
|
+
ac = table.schema.database.with_connection do |connection|
|
214
|
+
# wrapped in a transaction just in case something here fails, because
|
215
|
+
# we don't want the function, temporary table or trigger to be persisted
|
216
|
+
connection.exec("BEGIN")
|
217
|
+
|
218
|
+
# create the temp table and add the expected columns and constraint
|
219
|
+
connection.exec(<<~SQL)
|
220
|
+
CREATE TEMP TABLE trigger_normalized_action_condition_temp_table (
|
221
|
+
#{table.columns.map { |column| '"' + column.name.to_s + '" ' + column.temp_table_data_type.to_s }.join(", ")}
|
222
|
+
);
|
223
|
+
SQL
|
224
|
+
|
225
|
+
# create a temporary function to trigger (triggers require a function)
|
226
|
+
connection.exec(<<~SQL)
|
227
|
+
CREATE OR REPLACE FUNCTION trigger_normalized_action_condition_temp_fn() returns trigger language plpgsql AS
|
228
|
+
$$ BEGIN END $$;
|
229
|
+
SQL
|
230
|
+
|
231
|
+
# create a temporary trigger, from which we will fetch the normalized action condition
|
232
|
+
connection.exec(<<~SQL)
|
233
|
+
CREATE TRIGGER trigger_normalized_action_condition_temp_trigger
|
234
|
+
BEFORE UPDATE ON trigger_normalized_action_condition_temp_table
|
235
|
+
FOR EACH ROW
|
236
|
+
WHEN (#{action_condition})
|
237
|
+
EXECUTE FUNCTION trigger_normalized_action_condition_temp_fn();
|
238
|
+
SQL
|
239
|
+
|
240
|
+
# get the normalzed version of the action condition
|
241
|
+
rows = connection.exec(<<~SQL)
|
242
|
+
SELECT (
|
243
|
+
regexp_match(
|
244
|
+
pg_get_triggerdef(oid),
|
245
|
+
'.{35,} WHEN ((.+)) EXECUTE FUNCTION')
|
246
|
+
)[1] as action_condition
|
247
|
+
FROM pg_trigger
|
248
|
+
WHERE tgname = 'trigger_normalized_action_condition_temp_trigger'
|
249
|
+
;
|
250
|
+
SQL
|
251
|
+
|
252
|
+
# delete the temp table and close the transaction
|
253
|
+
connection.exec("ROLLBACK")
|
254
|
+
|
255
|
+
# return the normalized action condition
|
256
|
+
rows.first["action_condition"]
|
257
|
+
end
|
258
|
+
|
259
|
+
if ac.nil?
|
260
|
+
raise UnnormalizableActionConditionError, "Failed to nomalize action condition `#{action_condition}`"
|
261
|
+
end
|
262
|
+
|
263
|
+
ac
|
264
|
+
end
|
265
|
+
end
|
200
266
|
end
|
201
267
|
end
|
202
268
|
end
|
@@ -20,6 +20,9 @@ module DynamicMigrations
|
|
20
20
|
class UnexpectedTemplateError < StandardError
|
21
21
|
end
|
22
22
|
|
23
|
+
class UnnormalizableCheckClauseError < StandardError
|
24
|
+
end
|
25
|
+
|
23
26
|
attr_reader :table
|
24
27
|
attr_reader :name
|
25
28
|
attr_reader :check_clause
|
@@ -34,22 +37,25 @@ module DynamicMigrations
|
|
34
37
|
raise ExpectedTableError, table unless table.is_a? Table
|
35
38
|
@table = table
|
36
39
|
|
37
|
-
# assert that the provided columns is an array
|
38
|
-
unless columns.is_a?(Array) && columns.count > 0
|
39
|
-
raise ExpectedArrayOfColumnsError
|
40
|
-
end
|
41
|
-
|
42
|
-
@columns = {}
|
43
|
-
columns.each do |column|
|
44
|
-
add_column column
|
45
|
-
end
|
46
|
-
|
47
40
|
raise ExpectedSymbolError, name unless name.is_a? Symbol
|
48
41
|
@name = name
|
49
42
|
|
50
43
|
raise ExpectedStringError, check_clause unless check_clause.is_a? String
|
51
44
|
@check_clause = check_clause.strip
|
52
45
|
|
46
|
+
# if this validation is created via configuration (apposed to being loaded) then they can be lazy loaded
|
47
|
+
unless from_configuration? && columns.nil?
|
48
|
+
# assert that the provided columns is an array
|
49
|
+
unless columns.is_a?(Array) && columns.count > 0
|
50
|
+
raise ExpectedArrayOfColumnsError
|
51
|
+
end
|
52
|
+
|
53
|
+
@columns = {}
|
54
|
+
columns.each do |column|
|
55
|
+
add_column column
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
53
59
|
unless description.nil?
|
54
60
|
raise ExpectedStringError, description unless description.is_a? String
|
55
61
|
@description = description.strip
|
@@ -77,23 +83,100 @@ module DynamicMigrations
|
|
77
83
|
|
78
84
|
# return an array of this validations columns
|
79
85
|
def columns
|
86
|
+
if @columns.nil?
|
87
|
+
@columns = {}
|
88
|
+
normalized_check_clause_and_column_names[:column_names].each do |column_name|
|
89
|
+
add_column table.column(column_name)
|
90
|
+
end
|
91
|
+
end
|
80
92
|
@columns.values
|
81
93
|
end
|
82
94
|
|
83
95
|
def column_names
|
84
|
-
|
96
|
+
columns.map(&:name)
|
85
97
|
end
|
86
98
|
|
87
99
|
def differences_descriptions other_validation
|
88
100
|
method_differences_descriptions other_validation, [
|
89
|
-
:
|
101
|
+
:normalized_check_clause,
|
90
102
|
:deferrable,
|
91
103
|
:initially_deferred
|
92
104
|
]
|
93
105
|
end
|
94
106
|
|
107
|
+
# create a temporary table in postgres to represent this validation and fetch
|
108
|
+
# the actual normalized check constraint directly from the database
|
109
|
+
def normalized_check_clause
|
110
|
+
# no need to normalize check_clauses which originated from the database
|
111
|
+
if from_database?
|
112
|
+
check_clause
|
113
|
+
else
|
114
|
+
normalized_check_clause_and_column_names[:check_clause]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
95
118
|
private
|
96
119
|
|
120
|
+
def normalized_check_clause_and_column_names
|
121
|
+
@normalized_check_clause_and_column_names ||= fetch_normalized_check_clause_and_column_names
|
122
|
+
end
|
123
|
+
|
124
|
+
def fetch_normalized_check_clause_and_column_names
|
125
|
+
result = table.schema.database.with_connection do |connection|
|
126
|
+
# wrapped in a transaction just in case something here fails, because
|
127
|
+
# we don't want the temporary table to be persisted
|
128
|
+
connection.exec("BEGIN")
|
129
|
+
|
130
|
+
# create the temp table and add the expected columns and constraint
|
131
|
+
connection.exec(<<~SQL)
|
132
|
+
CREATE TEMP TABLE validation_normalized_check_clause_temp_table (
|
133
|
+
#{columns.map { |column| '"' + column.name.to_s + '" ' + column.temp_table_data_type.to_s }.join(", ")},
|
134
|
+
CONSTRAINT #{name} CHECK (#{check_clause})
|
135
|
+
);
|
136
|
+
SQL
|
137
|
+
|
138
|
+
# get the normalized version of the constraint
|
139
|
+
rows = connection.exec(<<~SQL)
|
140
|
+
SELECT
|
141
|
+
pg_get_constraintdef(pg_constraint.oid) AS check_clause,
|
142
|
+
ARRAY_AGG(col.attname ORDER BY u.attposition) AS column_names
|
143
|
+
FROM pg_constraint
|
144
|
+
LEFT JOIN LATERAL UNNEST(pg_constraint.conkey)
|
145
|
+
WITH ORDINALITY AS u(attnum, attposition)
|
146
|
+
ON TRUE
|
147
|
+
LEFT JOIN pg_attribute col
|
148
|
+
ON
|
149
|
+
(col.attrelid = pg_constraint.conrelid
|
150
|
+
AND col.attnum = u.attnum)
|
151
|
+
WHERE conrelid = 'validation_normalized_check_clause_temp_table'::regclass
|
152
|
+
GROUP BY pg_constraint.oid;
|
153
|
+
SQL
|
154
|
+
|
155
|
+
# delete the temp table and close the transaction
|
156
|
+
connection.exec("ROLLBACK")
|
157
|
+
|
158
|
+
rows.first
|
159
|
+
end
|
160
|
+
|
161
|
+
if result["check_clause"].nil?
|
162
|
+
raise UnnormalizableCheckClauseError, "Failed to nomalize check clause `#{check_clause}`"
|
163
|
+
end
|
164
|
+
|
165
|
+
# extract the check clause from the result "CHECK(%check_clause%)"
|
166
|
+
matches = result["check_clause"].match(/\ACHECK \((?<inner_clause>.*)\)\z/)
|
167
|
+
if matches.nil?
|
168
|
+
raise UnnormalizableCheckClauseError, "Unparsable normalized check_clause #{result["check_clause"]}"
|
169
|
+
end
|
170
|
+
|
171
|
+
normalized_column_names = result["column_names"].gsub(/\A\{/, "").gsub(/\}\Z/, "").split(",").map { |column_name| column_name.to_sym }
|
172
|
+
|
173
|
+
# return the normalized check clause
|
174
|
+
{
|
175
|
+
check_clause: matches[:inner_clause],
|
176
|
+
column_names: normalized_column_names
|
177
|
+
}
|
178
|
+
end
|
179
|
+
|
97
180
|
# used internally to set the columns from this objects initialize method
|
98
181
|
def add_column column
|
99
182
|
# assert that the provided dsl name is an array of Columns
|
@@ -42,7 +42,7 @@ module DynamicMigrations
|
|
42
42
|
if has_validation? name
|
43
43
|
raise(ValidationAlreadyExistsError, "Validation #{name} already exists")
|
44
44
|
end
|
45
|
-
columns = column_names
|
45
|
+
columns = column_names&.map { |column_name| column column_name }
|
46
46
|
included_target = self
|
47
47
|
if included_target.is_a? Table
|
48
48
|
new_validation = @validations[name] = Validation.new source, included_target, columns, name, check_clause, **validation_options
|
@@ -26,6 +26,7 @@ module DynamicMigrations
|
|
26
26
|
attr_reader :schema
|
27
27
|
attr_reader :name
|
28
28
|
attr_reader :description
|
29
|
+
attr_reader :remote_foreign_key_constraints
|
29
30
|
|
30
31
|
# initialize a new object to represent a postgres table
|
31
32
|
def initialize source, schema, name, description: nil
|
@@ -47,6 +48,7 @@ module DynamicMigrations
|
|
47
48
|
@validations = {}
|
48
49
|
@indexes = {}
|
49
50
|
@foreign_key_constraints = {}
|
51
|
+
@remote_foreign_key_constraints = []
|
50
52
|
@triggers = {}
|
51
53
|
@unique_constraints = {}
|
52
54
|
end
|
@@ -66,6 +66,14 @@ module DynamicMigrations
|
|
66
66
|
SQL
|
67
67
|
end
|
68
68
|
|
69
|
+
def refresh_database_structure_cache
|
70
|
+
connection.exec(<<~SQL)
|
71
|
+
REFRESH MATERIALIZED VIEW public.dynamic_migrations_structure_cache
|
72
|
+
SQL
|
73
|
+
rescue PG::UndefinedTable
|
74
|
+
create_database_structure_cache
|
75
|
+
end
|
76
|
+
|
69
77
|
# fetch all columns from the database and build and return a
|
70
78
|
# useful hash representing the structure of your database
|
71
79
|
def fetch_structure
|
@@ -100,7 +108,7 @@ module DynamicMigrations
|
|
100
108
|
|
101
109
|
column[:data_type] = row["data_type"].to_sym
|
102
110
|
column[:null] = row["is_nullable"] == "YES"
|
103
|
-
column[:is_enum] = row["is_enum"] == "
|
111
|
+
column[:is_enum] = row["is_enum"] == "t"
|
104
112
|
column[:default] = row["column_default"]
|
105
113
|
column[:description] = row["column_description"]
|
106
114
|
column[:interval_type] = row["interval_type"].nil? ? nil : row["interval_type"].to_sym
|
@@ -91,9 +91,10 @@ module DynamicMigrations
|
|
91
91
|
schema = schemas[event_object_schema] ||= {}
|
92
92
|
table = schema[event_object_table] ||= {}
|
93
93
|
|
94
|
-
#
|
95
|
-
|
96
|
-
|
94
|
+
# By convention (and to simplify things) we place the trigger and the triggers table in the same schema
|
95
|
+
# The function can be in a different schema (and often is, expecially for shared functions)
|
96
|
+
unless row["trigger_schema"] == row["event_object_schema"]
|
97
|
+
raise EventTriggerProcedureSchemaMismatchError, "Expected trigger and event_object to be in the same schema for trigger '#{trigger_name}'"
|
97
98
|
end
|
98
99
|
|
99
100
|
# turn the parameters into an array of strings
|
@@ -7,36 +7,35 @@ module DynamicMigrations
|
|
7
7
|
module ValidationsLoader
|
8
8
|
def create_database_validations_cache
|
9
9
|
connection.exec(<<~SQL)
|
10
|
-
CREATE MATERIALIZED VIEW public.dynamic_migrations_validations_cache
|
11
|
-
SELECT
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
CREATE MATERIALIZED VIEW public.dynamic_migrations_validations_cache AS
|
11
|
+
SELECT
|
12
|
+
nspname AS schema_name,
|
13
|
+
pg_constraint_class.relname AS table_name,
|
14
|
+
array_agg(columns.column_name ORDER BY columns.column_name) AS columns,
|
15
|
+
pg_get_constraintdef(pg_constraint.oid) AS check_clause,
|
16
|
+
conname AS validation_name,
|
17
|
+
obj_description(pg_constraint.oid, 'pg_constraint') AS description,
|
17
18
|
-- in case we need to update this query in a later version of DynamicMigrations
|
18
19
|
1 as table_version
|
19
|
-
FROM
|
20
|
-
JOIN
|
21
|
-
ON
|
22
|
-
|
23
|
-
|
24
|
-
JOIN
|
25
|
-
|
26
|
-
AND
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
table_constraints.constraint_name,
|
39
|
-
check_constraints.check_clause;
|
20
|
+
FROM pg_catalog.pg_constraint
|
21
|
+
INNER JOIN pg_catalog.pg_class pg_constraint_class
|
22
|
+
ON pg_constraint_class.oid = pg_constraint.conrelid
|
23
|
+
INNER JOIN pg_catalog.pg_namespace pg_constraint_namespace
|
24
|
+
ON pg_constraint_namespace.oid = connamespace
|
25
|
+
JOIN information_schema.columns
|
26
|
+
ON columns.table_schema = nspname
|
27
|
+
AND columns.table_name = pg_constraint_class.relname
|
28
|
+
AND columns.ordinal_position = ANY(pg_constraint.conkey)
|
29
|
+
WHERE
|
30
|
+
contype = 'c'
|
31
|
+
AND nspname != 'information_schema'
|
32
|
+
AND nspname != 'postgis'
|
33
|
+
AND left(nspname, 3) != 'pg_'
|
34
|
+
GROUP BY
|
35
|
+
pg_constraint.oid,
|
36
|
+
nspname,
|
37
|
+
pg_constraint_class.relname,
|
38
|
+
conname;
|
40
39
|
SQL
|
41
40
|
connection.exec(<<~SQL)
|
42
41
|
CREATE UNIQUE INDEX dynamic_migrations_validations_cache_index ON public.dynamic_migrations_validations_cache (schema_name, table_name, validation_name);
|
@@ -46,6 +45,14 @@ module DynamicMigrations
|
|
46
45
|
SQL
|
47
46
|
end
|
48
47
|
|
48
|
+
def refresh_database_validations_cache
|
49
|
+
connection.exec(<<~SQL)
|
50
|
+
REFRESH MATERIALIZED VIEW public.dynamic_migrations_validations_cache
|
51
|
+
SQL
|
52
|
+
rescue PG::UndefinedTable
|
53
|
+
create_database_validations_cache
|
54
|
+
end
|
55
|
+
|
49
56
|
# fetch all columns from the database and build and return a
|
50
57
|
# useful hash representing the validations of your database
|
51
58
|
def fetch_validations
|
@@ -70,9 +77,15 @@ module DynamicMigrations
|
|
70
77
|
|
71
78
|
validation_name = row["validation_name"].to_sym
|
72
79
|
|
80
|
+
matches = row["check_clause"].match(/\ACHECK \((?<inner_clause>.*)\)\z/)
|
81
|
+
if matches.nil?
|
82
|
+
raise StandardError, "Unparsable check_clause #{row["check_clause"]}"
|
83
|
+
end
|
84
|
+
check_clause = matches[:inner_clause]
|
85
|
+
|
73
86
|
table[validation_name] = {
|
74
87
|
columns: row["columns"].gsub(/\A\{/, "").gsub(/\}\Z/, "").split(",").map { |column_name| column_name.to_sym },
|
75
|
-
check_clause:
|
88
|
+
check_clause: check_clause,
|
76
89
|
description: row["description"],
|
77
90
|
deferrable: row["deferrable"] == "TRUE",
|
78
91
|
initially_deferred: row["initially_deferred"] == "TRUE"
|
@@ -55,6 +55,12 @@ module DynamicMigrations
|
|
55
55
|
def differences
|
56
56
|
Differences.new(self)
|
57
57
|
end
|
58
|
+
|
59
|
+
def refresh_caches
|
60
|
+
refresh_database_structure_cache
|
61
|
+
refresh_database_keys_and_unique_constraints_cache
|
62
|
+
refresh_database_validations_cache
|
63
|
+
end
|
58
64
|
end
|
59
65
|
end
|
60
66
|
end
|
data/lib/dynamic_migrations.rb
CHANGED
@@ -95,6 +95,7 @@ require "dynamic_migrations/active_record/migrators/trigger"
|
|
95
95
|
require "dynamic_migrations/active_record/migrators/table"
|
96
96
|
require "dynamic_migrations/active_record/migrators/index"
|
97
97
|
require "dynamic_migrations/active_record/migrators/enum"
|
98
|
+
require "dynamic_migrations/active_record/migrators/primary_key"
|
98
99
|
require "dynamic_migrations/active_record/migrators/column"
|
99
100
|
require "dynamic_migrations/active_record/migrators"
|
100
101
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# TypeProf 0.21.7
|
2
|
+
|
3
|
+
# Classes
|
4
|
+
module DynamicMigrations
|
5
|
+
module ActiveRecord
|
6
|
+
module Migrators
|
7
|
+
module PrimaryKey
|
8
|
+
def set_primary_key_comment: (Symbol table_name, Symbol primary_key_name, String comment) -> void
|
9
|
+
def remove_primary_key_comment: (Symbol table_name, Symbol primary_key_name) -> void
|
10
|
+
|
11
|
+
# stubbing these out, as they are available on the module which includes this module
|
12
|
+
def execute: (String sql) -> void
|
13
|
+
def schema_name: () -> Symbol
|
14
|
+
def quote: (String str) -> String
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -8,6 +8,8 @@ module DynamicMigrations
|
|
8
8
|
def add_primary_key: (Postgres::Server::Database::Schema::Table::PrimaryKey primary_key, ?String? code_comment) -> Fragment
|
9
9
|
def remove_primary_key: (Postgres::Server::Database::Schema::Table::PrimaryKey primary_key, ?String? code_comment) -> Fragment
|
10
10
|
def recreate_primary_key: (Postgres::Server::Database::Schema::Table::PrimaryKey original_primary_key, Postgres::Server::Database::Schema::Table::PrimaryKey updated_primary_key) -> Array[Fragment]
|
11
|
+
def set_primary_key_comment: (Postgres::Server::Database::Schema::Table::PrimaryKey primary_key, ?String? code_comment) -> Fragment
|
12
|
+
def remove_primary_key_comment: (Postgres::Server::Database::Schema::Table::PrimaryKey primary_key, ?String? code_comment) -> Fragment
|
11
13
|
|
12
14
|
# these come from the generator object (which this module is included into)
|
13
15
|
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?, ?dependent_function: Server::Database::Schema::Function?, ?dependent_enum: Server::Database::Schema::Enum?) -> Fragment
|
@@ -13,6 +13,8 @@ module DynamicMigrations
|
|
13
13
|
# these come from the generator object (which this module is included into)
|
14
14
|
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?, ?dependent_function: Server::Database::Schema::Function?, ?dependent_enum: Server::Database::Schema::Enum?) -> Fragment
|
15
15
|
def add_column: (Postgres::Server::Database::Schema::Table::Column column, ?String? code_comment) -> Fragment
|
16
|
+
def set_column_comment: (Postgres::Server::Database::Schema::Table::Column column, ?String? code_comment) -> Fragment
|
17
|
+
def set_primary_key_comment: (Postgres::Server::Database::Schema::Table::PrimaryKey primary_key, ?String? code_comment) -> Fragment
|
16
18
|
|
17
19
|
def indent: (String migration, ?Integer levels) -> String
|
18
20
|
|
@@ -6,20 +6,20 @@ module DynamicMigrations
|
|
6
6
|
class Generator
|
7
7
|
class ValidationTemplateBase
|
8
8
|
|
9
|
-
attr_reader validation:
|
9
|
+
attr_reader validation: Postgres::Server::Database::Schema::Table::Validation
|
10
10
|
attr_reader code_comment: String?
|
11
11
|
|
12
|
-
def initialize: (
|
12
|
+
def initialize: (Postgres::Server::Database::Schema::Table::Validation validation, String? code_comment) -> void
|
13
13
|
|
14
14
|
# abstract method (should actually be added to child classes)
|
15
15
|
def fragment_arguments: -> {schema: Postgres::Server::Database::Schema, table: Postgres::Server::Database::Schema::Table, migration_method: Symbol, object: untyped, code_comment: String?, migration: String, dependent_function: Postgres::Server::Database::Schema::Function?}
|
16
16
|
|
17
17
|
private
|
18
|
-
def assert_not_deferred!: ->
|
19
|
-
def assert_column_count!: (?Integer count) ->
|
20
|
-
def first_column: ->
|
21
|
-
def value_from_check_clause: (
|
22
|
-
def name_and_description_options_string: (
|
18
|
+
def assert_not_deferred!: -> void
|
19
|
+
def assert_column_count!: (?Integer count) -> void
|
20
|
+
def first_column: -> Postgres::Server::Database::Schema::Table::Column
|
21
|
+
def value_from_check_clause: (Regexp regex) -> untyped
|
22
|
+
def name_and_description_options_string: (Symbol default_name, ?String? default_comment) -> String?
|
23
23
|
def indent: (String multi_line_string, ?Integer levels) -> String
|
24
24
|
|
25
25
|
class TemplateError < StandardError
|
@@ -31,9 +31,9 @@ module DynamicMigrations
|
|
31
31
|
def supported_migration_method?: (Symbol migration_method) -> bool
|
32
32
|
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?, ?dependent_function: Server::Database::Schema::Function?, ?dependent_enum: Server::Database::Schema::Enum?) -> Fragment
|
33
33
|
def indent: (String migration, ?Integer levels) -> String
|
34
|
-
def strip_empty_lines: (String migration) -> String
|
35
34
|
def tsort_each_node: -> Enumerator[untyped, untyped]
|
36
35
|
def tsort_each_child: (untyped node) -> untyped
|
36
|
+
def trim_lines: (String migration) -> String
|
37
37
|
|
38
38
|
class ExpectedSymbolError < StandardError
|
39
39
|
end
|
@@ -8,7 +8,7 @@ module DynamicMigrations
|
|
8
8
|
def connect: -> PG::Connection
|
9
9
|
def connection: -> PG::Connection
|
10
10
|
def disconnect: -> void
|
11
|
-
def with_connection: ->
|
11
|
+
def with_connection: -> untyped
|
12
12
|
|
13
13
|
# these come from the database object (which this module is included into)
|
14
14
|
def name: -> Symbol
|
@@ -5,6 +5,7 @@ module DynamicMigrations
|
|
5
5
|
module KeysAndUniqueConstraintsLoader
|
6
6
|
def create_database_keys_and_unique_constraints_cache: -> void
|
7
7
|
def fetch_keys_and_unique_constraints: -> Hash[untyped, untyped]
|
8
|
+
def refresh_database_keys_and_unique_constraints_cache: -> void
|
8
9
|
|
9
10
|
# these come from the database object (which this module is included into)
|
10
11
|
def connection: -> PG::Connection
|
@@ -9,10 +9,10 @@ module DynamicMigrations
|
|
9
9
|
class Enum < Source
|
10
10
|
attr_reader schema: Schema
|
11
11
|
attr_reader name: Symbol
|
12
|
-
attr_reader values: Array[
|
12
|
+
attr_reader values: Array[String]
|
13
13
|
attr_reader description: String?
|
14
14
|
attr_reader columns: Array[Table::Column]
|
15
|
-
def initialize: (database_or_configuration source, Schema schema, Symbol name, Array[
|
15
|
+
def initialize: (database_or_configuration source, Schema schema, Symbol name, Array[String] values, ?description: String?) -> void
|
16
16
|
def full_name: -> Symbol
|
17
17
|
def has_description?: -> bool
|
18
18
|
def add_column: (Schema::Table::Column column) -> void
|
@@ -9,7 +9,7 @@ module DynamicMigrations
|
|
9
9
|
module Enums
|
10
10
|
@enums: Hash[Symbol, Enum]
|
11
11
|
|
12
|
-
def add_enum: (Symbol enum_name, Array[
|
12
|
+
def add_enum: (Symbol enum_name, Array[String] values, ?description: String?) -> nil
|
13
13
|
def enum: (Symbol enum_name) -> Enum
|
14
14
|
def has_enum?: (Symbol enum_name) -> bool
|
15
15
|
def enums: -> Array[Enum]
|
@@ -7,6 +7,8 @@ module DynamicMigrations
|
|
7
7
|
class Database
|
8
8
|
class Schema
|
9
9
|
class Function < Source
|
10
|
+
@normalized_definition: String?
|
11
|
+
|
10
12
|
attr_reader schema: Schema
|
11
13
|
attr_reader name: Symbol
|
12
14
|
attr_reader definition: String
|
@@ -16,12 +18,19 @@ module DynamicMigrations
|
|
16
18
|
def has_description?: -> bool
|
17
19
|
def add_trigger: (Schema::Table::Trigger trigger) -> void
|
18
20
|
def differences_descriptions: (Function other_function) -> Array[String]
|
21
|
+
def normalized_definition: -> String
|
22
|
+
|
23
|
+
private
|
24
|
+
def fetch_normalized_definition: -> String
|
19
25
|
|
20
26
|
class ExpectedSchemaError < StandardError
|
21
27
|
end
|
22
28
|
|
23
29
|
class ExpectedDefinitionError < StandardError
|
24
30
|
end
|
31
|
+
|
32
|
+
class UnnormalizableDefinitionError < StandardError
|
33
|
+
end
|
25
34
|
end
|
26
35
|
end
|
27
36
|
end
|
@@ -18,6 +18,10 @@ module DynamicMigrations
|
|
18
18
|
def initialize: (database_or_configuration source, Table table, Symbol name, Symbol data_type, ?null: bool, ?default: untyped, ?description: String?, ?interval_type: Symbol?, ?enum: Enum?) -> void
|
19
19
|
def has_description?: -> bool
|
20
20
|
def array?: -> bool
|
21
|
+
def enum?: -> bool
|
22
|
+
def temp_table_data_type: -> Symbol
|
23
|
+
# untyped because we cant specify this logic in rbs yet (compiler is concerned this might be nil)
|
24
|
+
def base_data_type: -> untyped
|
21
25
|
|
22
26
|
class ExpectedTableError < StandardError
|
23
27
|
end
|
data/sig/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraints.rbs
CHANGED
@@ -12,6 +12,7 @@ module DynamicMigrations
|
|
12
12
|
def foreign_key_constraints: -> Array[ForeignKeyConstraint]
|
13
13
|
def foreign_key_constraints_hash: -> Hash[Symbol, ForeignKeyConstraint]
|
14
14
|
def add_foreign_key_constraint: (Symbol name, Array[Symbol] column_names, Symbol foreign_schema_name, Symbol foreign_table_name, Array[Symbol] foreign_column_names, **untyped) -> untyped
|
15
|
+
def add_remote_foreign_key_constraint: (ForeignKeyConstraint foreign_key_constraint) -> untyped
|
15
16
|
|
16
17
|
# these come from the table object (which this module is included into)
|
17
18
|
def source: -> database_or_configuration
|