dynamic_migrations 3.6.16 → 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 +16 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/function.rb +1 -1
- data/lib/dynamic_migrations/postgres/server/database/schema/table/column.rb +6 -0
- 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 +2 -2
- data/lib/dynamic_migrations/postgres/server/database/schema/table/validation.rb +52 -24
- 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 +1 -1
- data/lib/dynamic_migrations/version.rb +1 -1
- data/sig/dynamic_migrations/postgres/server/database/schema/table/column.rbs +2 -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/validation.rbs +5 -3
- 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
- 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: 22fd29f59924e820da26858d1cf6caf04b03985ecc2fafd5f49205f5a0c2b34e
|
4
|
+
data.tar.gz: a8164cec22385ede8954df04e86c866bdb9d1ae4d420ba9107353f96e1a525e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec4eb2339d1ce110393eae8747c9e2aabee426d58a4e3caca8e01b7dd48ddfe99291ab903c9c7ba2e474a8b509a7185850132c1934f512c8ebe710e763243ba9
|
7
|
+
data.tar.gz: 50076bbed1405f301476ac49f0886207f9fde401c47af062fafa4095139cd3287699b8054cac4583b97422180f8fb3be935d94ac87b1ccd071a293972811eec7
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [3.7.0](https://github.com/craigulliott/dynamic_migrations/compare/v3.6.16...v3.7.0) (2023-09-27)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* providing access to foreign key constraints from both sides of the association ([48dcf1c](https://github.com/craigulliott/dynamic_migrations/commit/48dcf1cd4cdb23bc37da3e47b00f8007b8bc0f8a))
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* allowing foreign keys to the same table because they are valid and sometimes useful ([0566384](https://github.com/craigulliott/dynamic_migrations/commit/0566384a4cfeade757d9806059035477f7c41ee2))
|
14
|
+
* lazy loading column names for validations when they were configured with a nil value for columns ([439200e](https://github.com/craigulliott/dynamic_migrations/commit/439200efdedf74dddc852bf9bd35e81c1f6b4336))
|
15
|
+
* providing convenience method to retrieve columns base data type from array columns ([cd3d9bf](https://github.com/craigulliott/dynamic_migrations/commit/cd3d9bf06682335a890d9b11133d397d7bcd50af))
|
16
|
+
* semi colon at the end of function definitions is now optional ([ca9b3aa](https://github.com/craigulliott/dynamic_migrations/commit/ca9b3aa04da23605ff61b2ec14baed927145d2c3))
|
17
|
+
* structure loader was not identifying enums properly ([95276d3](https://github.com/craigulliott/dynamic_migrations/commit/95276d33f98f41eca9a9467bb6abeb458a37f16b))
|
18
|
+
|
3
19
|
## [3.6.16](https://github.com/craigulliott/dynamic_migrations/compare/v3.6.15...v3.6.16) (2023-09-16)
|
4
20
|
|
5
21
|
|
@@ -34,7 +34,7 @@ module DynamicMigrations
|
|
34
34
|
raise ExpectedSymbolError, name unless name.is_a? Symbol
|
35
35
|
@name = name
|
36
36
|
|
37
|
-
unless definition.is_a?(String) && definition.strip != "" && definition.strip.end_with?("END;")
|
37
|
+
unless definition.is_a?(String) && definition.strip != "" && definition.strip.end_with?("END;", "END")
|
38
38
|
raise ExpectedDefinitionError, "Definition must be a string, and end with `END;`. Definition provided:\n#{definition}"
|
39
39
|
end
|
40
40
|
@definition = definition.strip
|
@@ -77,6 +77,12 @@ module DynamicMigrations
|
|
77
77
|
!@enum.nil?
|
78
78
|
end
|
79
79
|
|
80
|
+
# for arrays returns the column type without the array brackets, for non arrays
|
81
|
+
# jsut returnms the column type
|
82
|
+
def base_data_type
|
83
|
+
array? ? @data_type[0..-3]&.to_sym : @data_type
|
84
|
+
end
|
85
|
+
|
80
86
|
# sometimes this system makes temporary tables in order to fetch the normalized
|
81
87
|
# version of constraint check clauses, function definitions or trigger action conditions
|
82
88
|
# because certain data types might not yet exist, we need to use alternative types
|
@@ -14,9 +14,6 @@ module DynamicMigrations
|
|
14
14
|
class ExpectedArrayOfColumnsError < StandardError
|
15
15
|
end
|
16
16
|
|
17
|
-
class ExpectedDifferentTablesError < StandardError
|
18
|
-
end
|
19
|
-
|
20
17
|
class DuplicateColumnError < StandardError
|
21
18
|
end
|
22
19
|
|
@@ -49,14 +46,14 @@ module DynamicMigrations
|
|
49
46
|
raise ExpectedArrayOfColumnsError
|
50
47
|
end
|
51
48
|
|
52
|
-
if table.name == foreign_table.name && table.schema.name == foreign_table.schema.name
|
53
|
-
raise ExpectedDifferentTablesError
|
54
|
-
end
|
55
|
-
|
56
49
|
# tables must be set before the columns are added
|
57
50
|
@table = table
|
58
51
|
@foreign_table = foreign_table
|
59
52
|
|
53
|
+
# add this foreign_key_constraint to the remote table (so we can always find
|
54
|
+
# these from both sides of the association)
|
55
|
+
@foreign_table.add_remote_foreign_key_constraint self
|
56
|
+
|
60
57
|
@columns = {}
|
61
58
|
columns.each do |column|
|
62
59
|
add_column column
|
data/lib/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraints.rb
CHANGED
@@ -61,6 +61,11 @@ module DynamicMigrations
|
|
61
61
|
# return the new foreign_key_constraint
|
62
62
|
new_foreign_key_constraint
|
63
63
|
end
|
64
|
+
|
65
|
+
# called automatically from the other side of the foreign key constraint to keep track of the foreign key from both sides
|
66
|
+
def add_remote_foreign_key_constraint foreign_key_constraint
|
67
|
+
@remote_foreign_key_constraints << foreign_key_constraint
|
68
|
+
end
|
64
69
|
end
|
65
70
|
end
|
66
71
|
end
|
@@ -54,7 +54,7 @@ module DynamicMigrations
|
|
54
54
|
attr_reader :description
|
55
55
|
attr_reader :template
|
56
56
|
|
57
|
-
# initialize a new object to represent a
|
57
|
+
# initialize a new object to represent a trigger in a postgres table
|
58
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
|
59
59
|
super source
|
60
60
|
|
@@ -201,7 +201,7 @@ module DynamicMigrations
|
|
201
201
|
descriptions
|
202
202
|
end
|
203
203
|
|
204
|
-
# create a temporary table in postgres to represent this
|
204
|
+
# create a temporary table in postgres to represent this trigger and fetch
|
205
205
|
# the actual normalized check constraint directly from the database
|
206
206
|
def normalized_action_condition
|
207
207
|
if action_condition.nil?
|
@@ -37,22 +37,25 @@ module DynamicMigrations
|
|
37
37
|
raise ExpectedTableError, table unless table.is_a? Table
|
38
38
|
@table = table
|
39
39
|
|
40
|
-
# assert that the provided columns is an array
|
41
|
-
unless columns.is_a?(Array) && columns.count > 0
|
42
|
-
raise ExpectedArrayOfColumnsError
|
43
|
-
end
|
44
|
-
|
45
|
-
@columns = {}
|
46
|
-
columns.each do |column|
|
47
|
-
add_column column
|
48
|
-
end
|
49
|
-
|
50
40
|
raise ExpectedSymbolError, name unless name.is_a? Symbol
|
51
41
|
@name = name
|
52
42
|
|
53
43
|
raise ExpectedStringError, check_clause unless check_clause.is_a? String
|
54
44
|
@check_clause = check_clause.strip
|
55
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
|
+
|
56
59
|
unless description.nil?
|
57
60
|
raise ExpectedStringError, description unless description.is_a? String
|
58
61
|
@description = description.strip
|
@@ -80,11 +83,17 @@ module DynamicMigrations
|
|
80
83
|
|
81
84
|
# return an array of this validations columns
|
82
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
|
83
92
|
@columns.values
|
84
93
|
end
|
85
94
|
|
86
95
|
def column_names
|
87
|
-
|
96
|
+
columns.map(&:name)
|
88
97
|
end
|
89
98
|
|
90
99
|
def differences_descriptions other_validation
|
@@ -102,15 +111,19 @@ module DynamicMigrations
|
|
102
111
|
if from_database?
|
103
112
|
check_clause
|
104
113
|
else
|
105
|
-
|
114
|
+
normalized_check_clause_and_column_names[:check_clause]
|
106
115
|
end
|
107
116
|
end
|
108
117
|
|
109
118
|
private
|
110
119
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
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
|
114
127
|
# we don't want the temporary table to be persisted
|
115
128
|
connection.exec("BEGIN")
|
116
129
|
|
@@ -122,31 +135,46 @@ module DynamicMigrations
|
|
122
135
|
);
|
123
136
|
SQL
|
124
137
|
|
125
|
-
# get the
|
138
|
+
# get the normalized version of the constraint
|
126
139
|
rows = connection.exec(<<~SQL)
|
127
|
-
SELECT
|
140
|
+
SELECT
|
141
|
+
pg_get_constraintdef(pg_constraint.oid) AS check_clause,
|
142
|
+
ARRAY_AGG(col.attname ORDER BY u.attposition) AS column_names
|
128
143
|
FROM pg_constraint
|
129
|
-
|
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;
|
130
153
|
SQL
|
131
154
|
|
132
155
|
# delete the temp table and close the transaction
|
133
156
|
connection.exec("ROLLBACK")
|
134
157
|
|
135
|
-
|
136
|
-
rows.first["check_clause"]
|
158
|
+
rows.first
|
137
159
|
end
|
138
160
|
|
139
|
-
if
|
161
|
+
if result["check_clause"].nil?
|
140
162
|
raise UnnormalizableCheckClauseError, "Failed to nomalize check clause `#{check_clause}`"
|
141
163
|
end
|
142
164
|
|
143
165
|
# extract the check clause from the result "CHECK(%check_clause%)"
|
144
|
-
matches =
|
166
|
+
matches = result["check_clause"].match(/\ACHECK \((?<inner_clause>.*)\)\z/)
|
145
167
|
if matches.nil?
|
146
|
-
raise UnnormalizableCheckClauseError, "Unparsable normalized check_clause #{
|
168
|
+
raise UnnormalizableCheckClauseError, "Unparsable normalized check_clause #{result["check_clause"]}"
|
147
169
|
end
|
148
170
|
|
149
|
-
|
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
|
+
}
|
150
178
|
end
|
151
179
|
|
152
180
|
# used internally to set the columns from this objects initialize method
|
@@ -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
|
@@ -108,7 +108,7 @@ module DynamicMigrations
|
|
108
108
|
|
109
109
|
column[:data_type] = row["data_type"].to_sym
|
110
110
|
column[:null] = row["is_nullable"] == "YES"
|
111
|
-
column[:is_enum] = row["is_enum"] == "
|
111
|
+
column[:is_enum] = row["is_enum"] == "t"
|
112
112
|
column[:default] = row["column_default"]
|
113
113
|
column[:description] = row["column_description"]
|
114
114
|
column[:interval_type] = row["interval_type"].nil? ? nil : row["interval_type"].to_sym
|
@@ -20,6 +20,8 @@ module DynamicMigrations
|
|
20
20
|
def array?: -> bool
|
21
21
|
def enum?: -> bool
|
22
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
|
23
25
|
|
24
26
|
class ExpectedTableError < StandardError
|
25
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
|
@@ -6,7 +6,7 @@ module DynamicMigrations
|
|
6
6
|
class Table
|
7
7
|
class Validation < Source
|
8
8
|
@columns: Hash[Symbol, Column]
|
9
|
-
@
|
9
|
+
@normalized_check_clause_and_column_names: {check_clause: String, column_names: Array[Symbol]}?
|
10
10
|
|
11
11
|
attr_reader table: Table
|
12
12
|
attr_reader name: Symbol
|
@@ -16,7 +16,7 @@ module DynamicMigrations
|
|
16
16
|
attr_reader description: String?
|
17
17
|
attr_reader template: Symbol?
|
18
18
|
|
19
|
-
def initialize: (database_or_configuration source, Table table, Array[Column] columns, Symbol name, String check_clause, ?deferrable: bool, ?initially_deferred: bool, ?description: String?, ?template: Symbol?) -> void
|
19
|
+
def initialize: (database_or_configuration source, Table table, Array[Column]? columns, Symbol name, String check_clause, ?deferrable: bool, ?initially_deferred: bool, ?description: String?, ?template: Symbol?) -> void
|
20
20
|
def columns: -> Array[Column]
|
21
21
|
def column_names: -> Array[Symbol]
|
22
22
|
def has_description?: -> bool
|
@@ -24,7 +24,9 @@ module DynamicMigrations
|
|
24
24
|
def normalized_check_clause: -> String
|
25
25
|
|
26
26
|
private
|
27
|
-
|
27
|
+
|
28
|
+
def normalized_check_clause_and_column_names: -> {check_clause: String, column_names: Array[Symbol]}
|
29
|
+
def fetch_normalized_check_clause_and_column_names: -> {check_clause: String, column_names: Array[Symbol]}
|
28
30
|
|
29
31
|
def add_column: (Column column) -> void
|
30
32
|
|
@@ -11,7 +11,7 @@ module DynamicMigrations
|
|
11
11
|
def has_validation?: (Symbol name) -> bool
|
12
12
|
def validations: -> Array[Validation]
|
13
13
|
def validations_hash: -> Hash[Symbol, Validation]
|
14
|
-
def add_validation: (Symbol name, Array[Symbol] column_names, String check_clause, **untyped) -> untyped
|
14
|
+
def add_validation: (Symbol name, Array[Symbol]? column_names, String check_clause, **untyped) -> untyped
|
15
15
|
|
16
16
|
# these come from the table object (which this module is included into)
|
17
17
|
def source: -> database_or_configuration
|
@@ -16,6 +16,7 @@ module DynamicMigrations
|
|
16
16
|
attr_reader schema: Schema
|
17
17
|
attr_reader name: Symbol
|
18
18
|
attr_reader description: String?
|
19
|
+
attr_reader remote_foreign_key_constraints: Array[ForeignKeyConstraint]
|
19
20
|
def initialize: (database_or_configuration source, Schema schema, Symbol name, ?description: String?) -> void
|
20
21
|
def has_description?: -> bool
|
21
22
|
def add_primary_key: (Symbol name, Array[Symbol] column_names, **untyped) -> untyped
|
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.7.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-09-
|
11
|
+
date: 2023-09-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|