dynamic_migrations 3.6.15 → 3.7.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 +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
|