dynamic_migrations 3.8.6 → 3.8.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -0
- data/lib/dynamic_migrations/active_record/migrators/validation.rb +2 -20
- data/lib/dynamic_migrations/postgres/generator/enum.rb +13 -9
- data/lib/dynamic_migrations/postgres/generator/fragment.rb +10 -3
- data/lib/dynamic_migrations/postgres/generator/function.rb +13 -13
- data/lib/dynamic_migrations/postgres/generator/migration.rb +45 -7
- data/lib/dynamic_migrations/postgres/generator/table_migration.rb +2 -0
- data/lib/dynamic_migrations/postgres/generator/validation.rb +1 -3
- data/lib/dynamic_migrations/postgres/generator/validation_template_base.rb +1 -7
- data/lib/dynamic_migrations/postgres/generator.rb +100 -46
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/extensions.rb +2 -2
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/enums.rb +10 -10
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/functions.rb +11 -11
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/columns.rb +11 -11
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/foreign_key_constraints.rb +11 -11
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/indexes.rb +11 -11
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/primary_key.rb +6 -6
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/triggers.rb +11 -11
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/unique_constraints.rb +11 -11
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/validations.rb +11 -11
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables.rb +8 -8
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas.rb +3 -3
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations.rb +4 -4
- data/lib/dynamic_migrations/postgres/server/database/differences.rb +25 -20
- data/lib/dynamic_migrations/postgres/server/database/keys_and_unique_constraints_loader.rb +2 -2
- data/lib/dynamic_migrations/postgres/server/database/loaded_schemas_builder.rb +1 -1
- data/lib/dynamic_migrations/postgres/server/database/schema/enum.rb +9 -2
- data/lib/dynamic_migrations/postgres/server/database/schema/function.rb +2 -2
- data/lib/dynamic_migrations/postgres/server/database/schema/table/column.rb +6 -2
- data/lib/dynamic_migrations/postgres/server/database/schema/table/columns.rb +0 -6
- data/lib/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraint.rb +6 -2
- data/lib/dynamic_migrations/postgres/server/database/schema/table/index.rb +7 -3
- data/lib/dynamic_migrations/postgres/server/database/schema/table/primary_key.rb +6 -2
- data/lib/dynamic_migrations/postgres/server/database/schema/table/trigger.rb +10 -8
- data/lib/dynamic_migrations/postgres/server/database/schema/table/triggers.rb +2 -2
- data/lib/dynamic_migrations/postgres/server/database/schema/table/unique_constraint.rb +6 -2
- data/lib/dynamic_migrations/postgres/server/database/schema/table/validation.rb +12 -19
- data/lib/dynamic_migrations/postgres/server/database/schema/table.rb +62 -2
- data/lib/dynamic_migrations/postgres/server/database/validations_loader.rb +1 -3
- data/lib/dynamic_migrations/version.rb +1 -1
- data/sig/dynamic_migrations/active_record/migrators/validation.rbs +1 -1
- data/sig/dynamic_migrations/postgres/generator/enum.rbs +2 -0
- data/sig/dynamic_migrations/postgres/generator/fragment.rbs +3 -0
- data/sig/dynamic_migrations/postgres/generator/function.rbs +1 -0
- data/sig/dynamic_migrations/postgres/generator/migration.rbs +1 -0
- data/sig/dynamic_migrations/postgres/generator/schema_migration.rbs +2 -0
- data/sig/dynamic_migrations/postgres/generator/table_migration.rbs +3 -0
- data/sig/dynamic_migrations/postgres/generator/validation_template_base.rbs +0 -1
- data/sig/dynamic_migrations/postgres/generator.rbs +3 -1
- data/sig/dynamic_migrations/postgres/server/database/schema/enum.rbs +3 -0
- data/sig/dynamic_migrations/postgres/server/database/schema/table/column.rbs +3 -0
- data/sig/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraint.rbs +3 -0
- data/sig/dynamic_migrations/postgres/server/database/schema/table/index.rbs +3 -0
- data/sig/dynamic_migrations/postgres/server/database/schema/table/primary_key.rbs +3 -0
- data/sig/dynamic_migrations/postgres/server/database/schema/table/trigger.rbs +3 -0
- data/sig/dynamic_migrations/postgres/server/database/schema/table/unique_constraint.rbs +3 -0
- data/sig/dynamic_migrations/postgres/server/database/schema/table/validation.rbs +4 -3
- data/sig/dynamic_migrations/postgres/server/database/schema/table.rbs +3 -0
- metadata +2 -3
- data/lib/dynamic_migrations/name_helper.rb +0 -13
@@ -23,6 +23,9 @@ module DynamicMigrations
|
|
23
23
|
class DuplicateColumnError < StandardError
|
24
24
|
end
|
25
25
|
|
26
|
+
class InvalidNameError < StandardError
|
27
|
+
end
|
28
|
+
|
26
29
|
attr_reader :table
|
27
30
|
attr_reader :name
|
28
31
|
attr_reader :deferrable
|
@@ -45,12 +48,13 @@ module DynamicMigrations
|
|
45
48
|
add_column column
|
46
49
|
end
|
47
50
|
|
48
|
-
raise
|
51
|
+
raise InvalidNameError, "Unexpected name `#{name}`. Name should be a Symbol" unless name.is_a? Symbol
|
52
|
+
raise InvalidNameError, "The name `#{name}` is too long. Names must be less than 64 characters" unless name.length < 64
|
49
53
|
@name = name
|
50
54
|
|
51
55
|
unless description.nil?
|
52
56
|
raise ExpectedStringError, description unless description.is_a? String
|
53
|
-
@description = description.strip
|
57
|
+
@description = description.strip.freeze
|
54
58
|
@description = nil if description == ""
|
55
59
|
end
|
56
60
|
|
@@ -26,25 +26,27 @@ module DynamicMigrations
|
|
26
26
|
class UnnormalizableCheckClauseError < StandardError
|
27
27
|
end
|
28
28
|
|
29
|
+
class InvalidNameError < StandardError
|
30
|
+
end
|
31
|
+
|
29
32
|
attr_reader :table
|
30
33
|
attr_reader :name
|
31
34
|
attr_reader :check_clause
|
32
|
-
attr_reader :deferrable
|
33
|
-
attr_reader :initially_deferred
|
34
35
|
attr_reader :description
|
35
36
|
attr_reader :template
|
36
37
|
|
37
38
|
# initialize a new object to represent a validation in a postgres table
|
38
|
-
def initialize source, table, columns, name, check_clause, description: nil,
|
39
|
+
def initialize source, table, columns, name, check_clause, description: nil, template: nil
|
39
40
|
super source
|
40
41
|
raise ExpectedTableError, table unless table.is_a? Table
|
41
42
|
@table = table
|
42
43
|
|
43
|
-
raise
|
44
|
+
raise InvalidNameError, "Unexpected name `#{name}`. Name should be a Symbol" unless name.is_a? Symbol
|
45
|
+
raise InvalidNameError, "The name `#{name}` is too long. Names must be less than 64 characters" unless name.length < 64
|
44
46
|
@name = name
|
45
47
|
|
46
48
|
raise ExpectedStringError, check_clause unless check_clause.is_a? String
|
47
|
-
@check_clause = check_clause.strip
|
49
|
+
@check_clause = check_clause.strip.freeze
|
48
50
|
|
49
51
|
# if this validation is created via configuration (apposed to being loaded) then they can be lazy loaded
|
50
52
|
unless from_configuration? && columns.nil?
|
@@ -61,16 +63,10 @@ module DynamicMigrations
|
|
61
63
|
|
62
64
|
unless description.nil?
|
63
65
|
raise ExpectedStringError, description unless description.is_a? String
|
64
|
-
@description = description.strip
|
66
|
+
@description = description.strip.freeze
|
65
67
|
@description = nil if description == ""
|
66
68
|
end
|
67
69
|
|
68
|
-
raise ExpectedBooleanError, deferrable unless [true, false].include?(deferrable)
|
69
|
-
@deferrable = deferrable
|
70
|
-
|
71
|
-
raise ExpectedBooleanError, initially_deferred unless [true, false].include?(initially_deferred)
|
72
|
-
@initially_deferred = initially_deferred
|
73
|
-
|
74
70
|
unless template.nil?
|
75
71
|
unless Generator::Validation.has_template? template
|
76
72
|
raise UnexpectedTemplateError, "Unrecognised template #{template}"
|
@@ -96,14 +92,12 @@ module DynamicMigrations
|
|
96
92
|
end
|
97
93
|
|
98
94
|
def column_names
|
99
|
-
columns.map(&:name)
|
95
|
+
columns.map(&:name).sort
|
100
96
|
end
|
101
97
|
|
102
98
|
def differences_descriptions other_validation
|
103
99
|
method_differences_descriptions other_validation, [
|
104
|
-
:normalized_check_clause
|
105
|
-
:deferrable,
|
106
|
-
:initially_deferred
|
100
|
+
:normalized_check_clause
|
107
101
|
]
|
108
102
|
end
|
109
103
|
|
@@ -134,7 +128,7 @@ module DynamicMigrations
|
|
134
128
|
|
135
129
|
temp_enums = table.create_temp_table(connection, "validation_normalized_check_clause_temp_table")
|
136
130
|
|
137
|
-
temp_check_clause = check_clause
|
131
|
+
temp_check_clause = check_clause.dup
|
138
132
|
# string replace any real enum names with their temp enum names
|
139
133
|
temp_enums.each do |temp_enum_name, enum|
|
140
134
|
temp_check_clause.gsub!("::#{enum.name}", "::#{temp_enum_name}")
|
@@ -182,8 +176,7 @@ module DynamicMigrations
|
|
182
176
|
|
183
177
|
# string replace any enum names with their real enum names
|
184
178
|
temp_enums.each do |temp_enum_name, enum|
|
185
|
-
|
186
|
-
check_clause_result.gsub!("::#{temp_enum_name}", "::#{real_enum_name}")
|
179
|
+
check_clause_result.gsub!("::#{temp_enum_name}", "::#{enum.full_name}")
|
187
180
|
end
|
188
181
|
|
189
182
|
column_names_result = column_names_string.gsub(/\A\{/, "").gsub(/\}\Z/, "").split(",").map { |column_name| column_name.to_sym }
|
@@ -16,6 +16,9 @@ module DynamicMigrations
|
|
16
16
|
class PrimaryKeyAlreadyExistsError < StandardError
|
17
17
|
end
|
18
18
|
|
19
|
+
class MissingExtensionError < StandardError
|
20
|
+
end
|
21
|
+
|
19
22
|
include Columns
|
20
23
|
include Validations
|
21
24
|
include Indexes
|
@@ -40,7 +43,7 @@ module DynamicMigrations
|
|
40
43
|
|
41
44
|
unless description.nil?
|
42
45
|
raise ExpectedStringError, description unless description.is_a? String
|
43
|
-
@description = description.strip
|
46
|
+
@description = description.strip.freeze
|
44
47
|
@description = nil if description == ""
|
45
48
|
end
|
46
49
|
|
@@ -116,7 +119,64 @@ module DynamicMigrations
|
|
116
119
|
end
|
117
120
|
|
118
121
|
# in case any of the columnbs are citext columns
|
119
|
-
|
122
|
+
# in case any of the columns use the citext data type
|
123
|
+
required_extensions = []
|
124
|
+
if columns.any? { |column| column.data_type.start_with? "citext" }
|
125
|
+
required_extensions << "citext"
|
126
|
+
end
|
127
|
+
if columns.any? { |column| column.data_type.start_with? "postgis" }
|
128
|
+
required_extensions << "postgis"
|
129
|
+
end
|
130
|
+
|
131
|
+
required_extensions.each do |extension_name|
|
132
|
+
extension_result = connection.exec(<<~SQL)
|
133
|
+
SELECT
|
134
|
+
(
|
135
|
+
SELECT 1
|
136
|
+
FROM pg_available_extensions
|
137
|
+
WHERE name = '#{extension_name}'
|
138
|
+
) as is_available,
|
139
|
+
(
|
140
|
+
SELECT 1
|
141
|
+
FROM pg_extension
|
142
|
+
WHERE extname = '#{extension_name}'
|
143
|
+
) as is_installed
|
144
|
+
SQL
|
145
|
+
|
146
|
+
row = extension_result.first
|
147
|
+
raise MissingExtensionError, "unexpected error" if row.nil?
|
148
|
+
|
149
|
+
unless row["is_installed"]
|
150
|
+
detail = if row["is_available"]
|
151
|
+
<<~DETAIL
|
152
|
+
The `#{extension_name}` extension is available for installation,
|
153
|
+
but has not been installed for this database.
|
154
|
+
DETAIL
|
155
|
+
else
|
156
|
+
<<~DETAIL
|
157
|
+
The `#{extension_name}` extension is not installed, and does not
|
158
|
+
appear to be available for installation.
|
159
|
+
DETAIL
|
160
|
+
end
|
161
|
+
raise MissingExtensionError, <<~ERROR.tr!("\n", " ")
|
162
|
+
This table uses the `#{extension_name}` data type. #{detail}
|
163
|
+
Add the extension, then generate and run the migrations which will
|
164
|
+
enable the extension for your database before defining validations
|
165
|
+
or triggers which rely on it.
|
166
|
+
|
167
|
+
Note, the `#{extension_name}` extension is required even for defining
|
168
|
+
some validations and triggers. This library needs to connect to postgres
|
169
|
+
and gererate normalized versions of validation check clauses and trigger
|
170
|
+
action conditions before it can even compare them to validations or triggers
|
171
|
+
which may or may not already exist in the database.
|
172
|
+
ERROR
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# if any of the columns require postgis
|
177
|
+
if required_extensions.include? "postgis"
|
178
|
+
connection.exec("SET search_path TO public,postgis;")
|
179
|
+
end
|
120
180
|
|
121
181
|
# note, this is not actually a TEMP TABLE, it is created within a transaction
|
122
182
|
# and rolled back.
|
@@ -86,9 +86,7 @@ module DynamicMigrations
|
|
86
86
|
table[validation_name] = {
|
87
87
|
columns: row["columns"].gsub(/\A\{/, "").gsub(/\}\Z/, "").split(",").map { |column_name| column_name.to_sym },
|
88
88
|
check_clause: check_clause,
|
89
|
-
description: row["description"]
|
90
|
-
deferrable: row["deferrable"] == "TRUE",
|
91
|
-
initially_deferred: row["initially_deferred"] == "TRUE"
|
89
|
+
description: row["description"]
|
92
90
|
}
|
93
91
|
end
|
94
92
|
schemas
|
@@ -5,7 +5,7 @@ module DynamicMigrations
|
|
5
5
|
module ActiveRecord
|
6
6
|
module Migrators
|
7
7
|
module Validation
|
8
|
-
def add_validation: (Symbol table_name, name: Symbol, ?
|
8
|
+
def add_validation: (Symbol table_name, name: Symbol, ?comment: String?) -> void
|
9
9
|
def remove_validation: (Symbol table_name, Symbol name) -> void
|
10
10
|
def set_validation_comment: (Symbol table_name, Symbol validation_name, String comment) -> void
|
11
11
|
def remove_validation_comment: (Symbol table_name, Symbol validation_name) -> void
|
@@ -10,6 +10,8 @@ module DynamicMigrations
|
|
10
10
|
def drop_enum: (Server::Database::Schema::Enum enum, ?String? code_comment) -> Fragment
|
11
11
|
def set_enum_comment: (Server::Database::Schema::Enum enum, ?String? code_comment) -> Fragment
|
12
12
|
def remove_enum_comment: (Server::Database::Schema::Enum enum, ?String? code_comment) -> Fragment
|
13
|
+
def optional_enum_table: (Postgres::Server::Database::Schema::Enum enum) -> Server::Database::Schema::Table?
|
14
|
+
|
13
15
|
# these come from the generator object (which this module is included into)
|
14
16
|
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
17
|
def indent: (String migration, ?Integer levels) -> String
|
@@ -10,6 +10,7 @@ module DynamicMigrations
|
|
10
10
|
def drop_function: (Postgres::Server::Database::Schema::Function function, ?String? code_comment) -> Fragment
|
11
11
|
def set_function_comment: (Postgres::Server::Database::Schema::Function function, ?String? code_comment) -> Fragment
|
12
12
|
def remove_function_comment: (Postgres::Server::Database::Schema::Function function, ?String? code_comment) -> Fragment
|
13
|
+
def optional_function_table: (Postgres::Server::Database::Schema::Function function) -> Server::Database::Schema::Table?
|
13
14
|
|
14
15
|
# these come from the generator object (which this module is included into)
|
15
16
|
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
|
@@ -22,6 +22,7 @@ module DynamicMigrations
|
|
22
22
|
def enum_dependencies: -> Array[{schema_name: Symbol, enum_name: Symbol}]
|
23
23
|
def function_dependencies: -> Array[{schema_name: Symbol, function_name: Symbol}]
|
24
24
|
|
25
|
+
def fragments_with_table_dependency_count: (Symbol schema_name, Symbol table_name) -> Integer
|
25
26
|
def extract_fragments_with_table_dependency: (Symbol schema_name, Symbol table_name) -> Array[Fragment]
|
26
27
|
|
27
28
|
def content: -> String
|
@@ -15,7 +15,6 @@ module DynamicMigrations
|
|
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!: -> void
|
19
18
|
def assert_column_count!: (?Integer count) -> void
|
20
19
|
def first_column: -> Postgres::Server::Database::Schema::Table::Column
|
21
20
|
def value_from_check_clause: (Regexp regex) -> untyped
|
@@ -7,6 +7,7 @@ module DynamicMigrations
|
|
7
7
|
include TSort
|
8
8
|
|
9
9
|
@fragments: Array[Fragment]
|
10
|
+
@logger: Logging::Logger
|
10
11
|
|
11
12
|
include Schema
|
12
13
|
include Table
|
@@ -27,13 +28,14 @@ module DynamicMigrations
|
|
27
28
|
}]
|
28
29
|
|
29
30
|
private
|
30
|
-
def
|
31
|
+
def resolve_circular_dependencies: (TableMigration table_migration, Array[TableMigration] all_table_migrations, Hash[Symbol, untyped] database_migrations, Array[TableMigration] completed_table_migrations, ?Array[String] stack) -> void
|
31
32
|
def supported_migration_method?: (Symbol migration_method) -> bool
|
32
33
|
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
34
|
def indent: (String migration, ?Integer levels) -> String
|
34
35
|
def tsort_each_node: -> Enumerator[untyped, untyped]
|
35
36
|
def tsort_each_child: (untyped node) -> untyped
|
36
37
|
def trim_lines: (String migration) -> String
|
38
|
+
def log: -> Logging::Logger
|
37
39
|
|
38
40
|
class ExpectedSymbolError < StandardError
|
39
41
|
end
|
@@ -11,12 +11,10 @@ module DynamicMigrations
|
|
11
11
|
attr_reader table: Table
|
12
12
|
attr_reader name: Symbol
|
13
13
|
attr_reader check_clause: String
|
14
|
-
attr_reader deferrable: bool
|
15
|
-
attr_reader initially_deferred: bool
|
16
14
|
attr_reader description: String?
|
17
15
|
attr_reader template: Symbol?
|
18
16
|
|
19
|
-
def initialize: (database_or_configuration source, Table table, Array[Column]? columns, Symbol name, String check_clause, ?
|
17
|
+
def initialize: (database_or_configuration source, Table table, Array[Column]? columns, Symbol name, String check_clause, ?description: String?, ?template: Symbol?) -> void
|
20
18
|
def columns: -> Array[Column]
|
21
19
|
def column_names: -> Array[Symbol]
|
22
20
|
def has_description?: -> bool
|
@@ -50,6 +48,9 @@ module DynamicMigrations
|
|
50
48
|
|
51
49
|
class UnnormalizableCheckClauseError < StandardError
|
52
50
|
end
|
51
|
+
|
52
|
+
class InvalidNameError < StandardError
|
53
|
+
end
|
53
54
|
end
|
54
55
|
end
|
55
56
|
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.8.
|
4
|
+
version: 3.8.8
|
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-10-
|
11
|
+
date: 2023-10-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -96,7 +96,6 @@ files:
|
|
96
96
|
- lib/dynamic_migrations/expected_symbol_error.rb
|
97
97
|
- lib/dynamic_migrations/invalid_source_error.rb
|
98
98
|
- lib/dynamic_migrations/module_included_into_unexpected_target_error.rb
|
99
|
-
- lib/dynamic_migrations/name_helper.rb
|
100
99
|
- lib/dynamic_migrations/postgres.rb
|
101
100
|
- lib/dynamic_migrations/postgres/connections.rb
|
102
101
|
- lib/dynamic_migrations/postgres/generator.rb
|
@@ -1,13 +0,0 @@
|
|
1
|
-
module DynamicMigrations
|
2
|
-
module NameHelper
|
3
|
-
# shortens a table name like 'invoice_subscription_prepayments' to 'inv_sub_pre'
|
4
|
-
warn "no unit tests"
|
5
|
-
def abbreviate_table_name table_name
|
6
|
-
table_name_without_schema = table_name.to_s.split(".").last
|
7
|
-
if table_name_without_schema.nil?
|
8
|
-
raise "no table name provided"
|
9
|
-
end
|
10
|
-
table_name_without_schema.split("_").map { |v| v[0..2] }.join("_")
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|