dynamic_migrations 3.1.0 → 3.2.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 +14 -0
- data/lib/dynamic_migrations/postgres/generator/column.rb +44 -19
- data/lib/dynamic_migrations/postgres/generator/foreign_key_constraint.rb +35 -14
- data/lib/dynamic_migrations/postgres/generator/fragment.rb +37 -2
- data/lib/dynamic_migrations/postgres/generator/function.rb +50 -25
- data/lib/dynamic_migrations/postgres/generator/index.rb +34 -14
- data/lib/dynamic_migrations/postgres/generator/migration.rb +175 -0
- data/lib/dynamic_migrations/postgres/generator/migration_dependency_sorter.rb +21 -0
- data/lib/dynamic_migrations/postgres/generator/primary_key.rb +16 -6
- data/lib/dynamic_migrations/postgres/generator/schema.rb +14 -6
- data/lib/dynamic_migrations/postgres/generator/schema_migration.rb +17 -0
- data/lib/dynamic_migrations/postgres/generator/table.rb +39 -19
- data/lib/dynamic_migrations/postgres/generator/table_migration.rb +51 -0
- data/lib/dynamic_migrations/postgres/generator/trigger.rb +34 -14
- data/lib/dynamic_migrations/postgres/generator/unique_constraint.rb +34 -14
- data/lib/dynamic_migrations/postgres/generator/validation.rb +38 -18
- data/lib/dynamic_migrations/postgres/generator.rb +163 -294
- data/lib/dynamic_migrations/postgres/server/database/connection.rb +15 -0
- data/lib/dynamic_migrations/version.rb +1 -1
- data/lib/dynamic_migrations.rb +4 -2
- metadata +6 -4
- data/lib/dynamic_migrations/postgres/generator/schema_migrations/section.rb +0 -37
- data/lib/dynamic_migrations/postgres/generator/schema_migrations.rb +0 -92
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '05957cccec4b1ee5138e9e74daa7714da41b99be958f7171e1c88475fe495e7b'
|
4
|
+
data.tar.gz: fd7cb71f07ded6599286dac27c274832bf97de43e56b69a47b7238aefaac2cde
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1729685ce54c91e0a3a8ce03fbb552887450b843f4c654678717aba41c1e52b66dff1104b9acaedd955e221267619e64405fe4088af9de54b9216446bf87984
|
7
|
+
data.tar.gz: 95668080a1d329fcaf0172e3593cfc59bab34b7edca05fedfe23d10d7b83945bd9c79943768765f505997fdd8781721569b2845d752d8f99450d251758d41eac
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [3.2.0](https://github.com/craigulliott/dynamic_migrations/compare/v3.1.1...v3.2.0) (2023-08-16)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* adding a with_connection method to the database which yields to a block, and provides a connection object to that block ([fc1590a](https://github.com/craigulliott/dynamic_migrations/commit/fc1590a00be8d3f9f0ee0472a96be94b80e667e0))
|
9
|
+
|
10
|
+
## [3.1.1](https://github.com/craigulliott/dynamic_migrations/compare/v3.1.0...v3.1.1) (2023-08-16)
|
11
|
+
|
12
|
+
|
13
|
+
### Bug Fixes
|
14
|
+
|
15
|
+
* refactoring the migration generator so that it handles dependencies between migrations ([8d0f8d8](https://github.com/craigulliott/dynamic_migrations/commit/8d0f8d8cd4a22b974b6449c62ad2a2d74aeffb2e))
|
16
|
+
|
3
17
|
## [3.1.0](https://github.com/craigulliott/dynamic_migrations/compare/v3.0.0...v3.1.0) (2023-08-14)
|
4
18
|
|
5
19
|
|
@@ -28,11 +28,16 @@ module DynamicMigrations
|
|
28
28
|
data_type = "\"#{data_type}\""
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
add_fragment schema: column.table.schema,
|
32
|
+
table: column.table,
|
33
|
+
migration_method: :add_column,
|
34
|
+
object: column,
|
35
|
+
code_comment: code_comment,
|
36
|
+
migration: <<~RUBY
|
37
|
+
add_column :#{column.table.name}, :#{column.name}, :#{data_type}, #{options_syntax}, comment: <<~COMMENT
|
38
|
+
#{indent column.description}
|
39
|
+
COMMENT
|
40
|
+
RUBY
|
36
41
|
end
|
37
42
|
|
38
43
|
def change_column column, code_comment = nil
|
@@ -54,15 +59,25 @@ module DynamicMigrations
|
|
54
59
|
data_type = ":\"#{data_type}\""
|
55
60
|
end
|
56
61
|
|
57
|
-
|
58
|
-
|
59
|
-
|
62
|
+
add_fragment schema: column.table.schema,
|
63
|
+
table: column.table,
|
64
|
+
migration_method: :change_column,
|
65
|
+
object: column,
|
66
|
+
code_comment: code_comment,
|
67
|
+
migration: <<~RUBY
|
68
|
+
change_column :#{column.table.name}, :#{column.name}, :#{data_type}, #{options_syntax}
|
69
|
+
RUBY
|
60
70
|
end
|
61
71
|
|
62
72
|
def remove_column column, code_comment = nil
|
63
|
-
|
64
|
-
|
65
|
-
|
73
|
+
add_fragment schema: column.table.schema,
|
74
|
+
table: column.table,
|
75
|
+
migration_method: :remove_column,
|
76
|
+
object: column,
|
77
|
+
code_comment: code_comment,
|
78
|
+
migration: <<~RUBY
|
79
|
+
remove_column :#{column.table.name}, :#{column.name}
|
80
|
+
RUBY
|
66
81
|
end
|
67
82
|
|
68
83
|
# add a comment to a column
|
@@ -73,18 +88,28 @@ module DynamicMigrations
|
|
73
88
|
raise MissingDescriptionError
|
74
89
|
end
|
75
90
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
91
|
+
add_fragment schema: column.table.schema,
|
92
|
+
table: column.table,
|
93
|
+
migration_method: :set_column_comment,
|
94
|
+
object: column,
|
95
|
+
code_comment: code_comment,
|
96
|
+
migration: <<~RUBY
|
97
|
+
set_column_comment :#{column.table.name}, :#{column.name}, <<~COMMENT
|
98
|
+
#{indent description}
|
99
|
+
COMMENT
|
100
|
+
RUBY
|
81
101
|
end
|
82
102
|
|
83
103
|
# remove the comment from a column
|
84
104
|
def remove_column_comment column, code_comment = nil
|
85
|
-
|
86
|
-
|
87
|
-
|
105
|
+
add_fragment schema: column.table.schema,
|
106
|
+
table: column.table,
|
107
|
+
migration_method: :remove_column_comment,
|
108
|
+
object: column,
|
109
|
+
code_comment: code_comment,
|
110
|
+
migration: <<~RUBY
|
111
|
+
remove_column_comment :#{column.table.name}, :#{column.name}
|
112
|
+
RUBY
|
88
113
|
end
|
89
114
|
end
|
90
115
|
end
|
@@ -29,15 +29,26 @@ module DynamicMigrations
|
|
29
29
|
|
30
30
|
options_syntax = options.map { |k, v| "#{k}: #{v}" }.join(", ")
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
add_fragment schema: foreign_key_constraint.table.schema,
|
33
|
+
table: foreign_key_constraint.table,
|
34
|
+
migration_method: :add_foreign_key,
|
35
|
+
object: foreign_key_constraint,
|
36
|
+
code_comment: code_comment,
|
37
|
+
dependent_table: foreign_key_constraint.foreign_table,
|
38
|
+
migration: <<~RUBY
|
39
|
+
add_foreign_key :#{foreign_key_constraint.table.name}, #{column_names}, :#{foreign_key_constraint.foreign_table.name}, #{foreign_column_names}, #{options_syntax}
|
40
|
+
RUBY
|
35
41
|
end
|
36
42
|
|
37
43
|
def remove_foreign_key_constraint foreign_key_constraint, code_comment = nil
|
38
|
-
|
39
|
-
|
40
|
-
|
44
|
+
add_fragment schema: foreign_key_constraint.table.schema,
|
45
|
+
table: foreign_key_constraint.table,
|
46
|
+
migration_method: :remove_foreign_key,
|
47
|
+
object: foreign_key_constraint,
|
48
|
+
code_comment: code_comment,
|
49
|
+
migration: <<~RUBY
|
50
|
+
remove_foreign_key :#{foreign_key_constraint.table.name}, :#{foreign_key_constraint.name}
|
51
|
+
RUBY
|
41
52
|
end
|
42
53
|
|
43
54
|
def recreate_foreign_key_constraint original_foreign_key_constraint, updated_foreign_key_constraint
|
@@ -65,18 +76,28 @@ module DynamicMigrations
|
|
65
76
|
raise MissingDescriptionError
|
66
77
|
end
|
67
78
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
79
|
+
add_fragment schema: foreign_key_constraint.table.schema,
|
80
|
+
table: foreign_key_constraint.table,
|
81
|
+
migration_method: :set_foreign_key_constraint_comment,
|
82
|
+
object: foreign_key_constraint,
|
83
|
+
code_comment: code_comment,
|
84
|
+
migration: <<~RUBY
|
85
|
+
set_foreign_key_comment :#{foreign_key_constraint.table.name}, :#{foreign_key_constraint.name}, <<~COMMENT
|
86
|
+
#{indent description}
|
87
|
+
COMMENT
|
88
|
+
RUBY
|
73
89
|
end
|
74
90
|
|
75
91
|
# remove the comment from a foreign_key_constraint
|
76
92
|
def remove_foreign_key_constraint_comment foreign_key_constraint, code_comment = nil
|
77
|
-
|
78
|
-
|
79
|
-
|
93
|
+
add_fragment schema: foreign_key_constraint.table.schema,
|
94
|
+
table: foreign_key_constraint.table,
|
95
|
+
migration_method: :remove_foreign_key_constraint_comment,
|
96
|
+
object: foreign_key_constraint,
|
97
|
+
code_comment: code_comment,
|
98
|
+
migration: <<~RUBY
|
99
|
+
remove_foreign_key_comment :#{foreign_key_constraint.table.name}, :#{foreign_key_constraint.name}
|
100
|
+
RUBY
|
80
101
|
end
|
81
102
|
end
|
82
103
|
end
|
@@ -2,15 +2,25 @@ module DynamicMigrations
|
|
2
2
|
module Postgres
|
3
3
|
class Generator
|
4
4
|
class Fragment
|
5
|
+
attr_reader :schema_name
|
6
|
+
attr_reader :table_name
|
7
|
+
attr_reader :migration_method
|
5
8
|
attr_reader :object_name
|
6
|
-
attr_reader :
|
9
|
+
attr_reader :dependency_schema_name
|
10
|
+
attr_reader :dependency_table_name
|
7
11
|
|
8
|
-
def initialize object_name, code_comment, content
|
12
|
+
def initialize schema_name, table_name, migration_method, object_name, code_comment, content
|
13
|
+
@schema_name = schema_name
|
14
|
+
@table_name = table_name
|
15
|
+
@migration_method = migration_method
|
9
16
|
@object_name = object_name
|
10
17
|
@code_comment = code_comment
|
11
18
|
@content = content
|
12
19
|
end
|
13
20
|
|
21
|
+
# Returns a string representation of the fragment for use in the final
|
22
|
+
# migration. This final string is a combination of the code_comment (if present)
|
23
|
+
# and the content of the fragment.
|
14
24
|
def to_s
|
15
25
|
strings = []
|
16
26
|
comment = @code_comment
|
@@ -21,9 +31,34 @@ module DynamicMigrations
|
|
21
31
|
strings.join("\n").strip
|
22
32
|
end
|
23
33
|
|
34
|
+
# Returns true if the fragment has a code comment, otherwise false.
|
24
35
|
def has_code_comment?
|
25
36
|
!@code_comment.nil?
|
26
37
|
end
|
38
|
+
|
39
|
+
# If a table dependency has been set, then returns a hash with the schema_name
|
40
|
+
# and table_name, otherwise returns nil.
|
41
|
+
def dependency
|
42
|
+
if dependency_schema_name && dependency_table_name
|
43
|
+
{
|
44
|
+
schema_name: dependency_schema_name,
|
45
|
+
table_name: dependency_table_name
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# returns true if the fragment has a table dependency, and the dependency matches
|
51
|
+
# the provided schema_name and table_name, otherwise returns false.
|
52
|
+
def is_dependent_on? schema_name, table_name
|
53
|
+
dependency_schema_name && schema_name == dependency_schema_name && table_name == dependency_table_name || false
|
54
|
+
end
|
55
|
+
|
56
|
+
# Set the table table dependency for this fragment. Takes a schema name and
|
57
|
+
# table name
|
58
|
+
def set_dependent_table schema_name, table_name
|
59
|
+
@dependency_schema_name = schema_name
|
60
|
+
@dependency_table_name = table_name
|
61
|
+
end
|
27
62
|
end
|
28
63
|
end
|
29
64
|
end
|
@@ -25,13 +25,18 @@ module DynamicMigrations
|
|
25
25
|
fn_sql << ";"
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
28
|
+
add_fragment schema: function.schema,
|
29
|
+
table: function.triggers.first&.table,
|
30
|
+
migration_method: :create_function,
|
31
|
+
object: function,
|
32
|
+
code_comment: code_comment,
|
33
|
+
migration: comment_sql + <<~RUBY
|
34
|
+
create_function :#{function.name}#{optional_options_syntax} do
|
35
|
+
<<~SQL
|
36
|
+
#{indent fn_sql}
|
37
|
+
SQL
|
38
|
+
end
|
39
|
+
RUBY
|
35
40
|
end
|
36
41
|
|
37
42
|
def update_function function, code_comment = nil
|
@@ -41,35 +46,55 @@ module DynamicMigrations
|
|
41
46
|
fn_sql << ";"
|
42
47
|
end
|
43
48
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
49
|
+
add_fragment schema: function.schema,
|
50
|
+
table: function.triggers.first&.table,
|
51
|
+
migration_method: :update_function,
|
52
|
+
object: function,
|
53
|
+
code_comment: code_comment,
|
54
|
+
migration: <<~RUBY
|
55
|
+
update_function :#{function.name} do
|
56
|
+
<<~SQL
|
57
|
+
#{indent fn_sql}
|
58
|
+
SQL
|
59
|
+
end
|
60
|
+
RUBY
|
51
61
|
end
|
52
62
|
|
53
63
|
def drop_function function, code_comment = nil
|
54
|
-
|
55
|
-
|
56
|
-
|
64
|
+
add_fragment schema: function.schema,
|
65
|
+
table: function.triggers.first&.table,
|
66
|
+
migration_method: :drop_function,
|
67
|
+
object: function,
|
68
|
+
code_comment: code_comment,
|
69
|
+
migration: <<~RUBY
|
70
|
+
drop_function :#{function.name}
|
71
|
+
RUBY
|
57
72
|
end
|
58
73
|
|
59
74
|
# add a comment to a function
|
60
75
|
def set_function_comment function, code_comment = nil
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
76
|
+
add_fragment schema: function.schema,
|
77
|
+
table: function.triggers.first&.table,
|
78
|
+
migration_method: :set_function_comment,
|
79
|
+
object: function,
|
80
|
+
code_comment: code_comment,
|
81
|
+
migration: <<~RUBY
|
82
|
+
set_function_comment :#{function.name}, <<~COMMENT
|
83
|
+
#{indent function.description || ""}
|
84
|
+
COMMENT
|
85
|
+
RUBY
|
66
86
|
end
|
67
87
|
|
68
88
|
# remove the comment from a function
|
69
89
|
def remove_function_comment function, code_comment = nil
|
70
|
-
|
71
|
-
|
72
|
-
|
90
|
+
add_fragment schema: function.schema,
|
91
|
+
table: function.triggers.first&.table,
|
92
|
+
migration_method: :remove_function_comment,
|
93
|
+
object: function,
|
94
|
+
code_comment: code_comment,
|
95
|
+
migration: <<~RUBY
|
96
|
+
remove_function_comment :#{function.name}
|
97
|
+
RUBY
|
73
98
|
end
|
74
99
|
end
|
75
100
|
end
|
@@ -46,15 +46,25 @@ module DynamicMigrations
|
|
46
46
|
|
47
47
|
options_syntax = options.map { |k, v| "#{k}: #{v}" }.join(", ")
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
add_fragment schema: index.table.schema,
|
50
|
+
table: index.table,
|
51
|
+
migration_method: :add_index,
|
52
|
+
object: index,
|
53
|
+
code_comment: code_comment,
|
54
|
+
migration: where_sql + <<~RUBY
|
55
|
+
add_index :#{index.table.name}, #{column_names}, #{options_syntax}
|
56
|
+
RUBY
|
52
57
|
end
|
53
58
|
|
54
59
|
def remove_index index, code_comment = nil
|
55
|
-
|
56
|
-
|
57
|
-
|
60
|
+
add_fragment schema: index.table.schema,
|
61
|
+
table: index.table,
|
62
|
+
migration_method: :remove_index,
|
63
|
+
object: index,
|
64
|
+
code_comment: code_comment,
|
65
|
+
migration: <<~RUBY
|
66
|
+
remove_index :#{index.table.name}, :#{index.name}
|
67
|
+
RUBY
|
58
68
|
end
|
59
69
|
|
60
70
|
def recreate_index original_index, updated_index
|
@@ -82,18 +92,28 @@ module DynamicMigrations
|
|
82
92
|
raise MissingDescriptionError
|
83
93
|
end
|
84
94
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
95
|
+
add_fragment schema: index.table.schema,
|
96
|
+
table: index.table,
|
97
|
+
migration_method: :set_index_comment,
|
98
|
+
object: index,
|
99
|
+
code_comment: code_comment,
|
100
|
+
migration: <<~RUBY
|
101
|
+
set_index_comment :#{index.table.name}, :#{index.name}, <<~COMMENT
|
102
|
+
#{indent description}
|
103
|
+
COMMENT
|
104
|
+
RUBY
|
90
105
|
end
|
91
106
|
|
92
107
|
# remove the comment from a index
|
93
108
|
def remove_index_comment index, code_comment = nil
|
94
|
-
|
95
|
-
|
96
|
-
|
109
|
+
add_fragment schema: index.table.schema,
|
110
|
+
table: index.table,
|
111
|
+
migration_method: :remove_index_comment,
|
112
|
+
object: index,
|
113
|
+
code_comment: code_comment,
|
114
|
+
migration: <<~RUBY
|
115
|
+
remove_index_comment :#{index.table.name}, :#{index.name}
|
116
|
+
RUBY
|
97
117
|
end
|
98
118
|
end
|
99
119
|
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
module DynamicMigrations
|
2
|
+
module Postgres
|
3
|
+
class Generator
|
4
|
+
class Migration
|
5
|
+
class UnexpectedSchemaError < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
class SectionNotFoundError < StandardError
|
9
|
+
end
|
10
|
+
|
11
|
+
class UnexpectedMigrationMethodNameError < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
class DuplicateStructureTemplateError < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
class NoFragmentsError < StandardError
|
18
|
+
end
|
19
|
+
|
20
|
+
# Defines a new section in the migration file, this is used to group
|
21
|
+
# migration fragments of the provided method names together under the
|
22
|
+
# provided header
|
23
|
+
def self.add_structure_template method_names, header
|
24
|
+
@structure_templates ||= []
|
25
|
+
|
26
|
+
if (@structure_templates.map { |s| s[:methods] }.flatten & method_names).any?
|
27
|
+
raise DuplicateStructureTemplateError, "Duplicate structure template for methods `#{method_names}`"
|
28
|
+
end
|
29
|
+
|
30
|
+
@structure_templates << {
|
31
|
+
methods: method_names,
|
32
|
+
header_comment: <<~COMMENT.strip
|
33
|
+
#
|
34
|
+
# #{header.strip}
|
35
|
+
#
|
36
|
+
COMMENT
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
# return the list of structure templates for use in this migration
|
41
|
+
def self.structure_templates
|
42
|
+
@structure_templates || []
|
43
|
+
end
|
44
|
+
|
45
|
+
# return the list of structure templates for use in this migration
|
46
|
+
def self.clear_structure_templates
|
47
|
+
@structure_templates = []
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_reader :schema_name
|
51
|
+
attr_reader :fragments
|
52
|
+
|
53
|
+
def initialize schema_name
|
54
|
+
@schema_name = schema_name
|
55
|
+
@fragments = []
|
56
|
+
end
|
57
|
+
|
58
|
+
# Add a migration fragment to this migration, if the migration is not
|
59
|
+
# configured (via a structure template) to handle the method_name of the
|
60
|
+
# fragment, then am error is raised. An error will also be raised if the
|
61
|
+
# migration belongs to a different schema than the provided fragment.
|
62
|
+
def add_fragment fragment
|
63
|
+
raise UnexpectedSchemaError unless @schema_name == fragment.schema_name
|
64
|
+
|
65
|
+
unless supported_migration_method? fragment.migration_method
|
66
|
+
raise UnexpectedMigrationMethodNameError, "Expected method to be a valid migrator method, got `#{fragment.migration_method}`"
|
67
|
+
end
|
68
|
+
|
69
|
+
@fragments << fragment
|
70
|
+
|
71
|
+
fragment
|
72
|
+
end
|
73
|
+
|
74
|
+
# Return an array of table dependencies for this migration, this array comes from
|
75
|
+
# combining any table dependencies from each fragment.
|
76
|
+
# Will raise an error if no fragments have been provided.
|
77
|
+
def dependencies
|
78
|
+
raise NoFragmentsError if fragments.empty?
|
79
|
+
@fragments.map(&:dependency).compact
|
80
|
+
end
|
81
|
+
|
82
|
+
# removes and returns any fragments which have a dependency on the table with the
|
83
|
+
# provided schema_name and table_name, this is used for extracting fragments which
|
84
|
+
# cause circular dependencies so they can be placed into their own migrations
|
85
|
+
def extract_fragments_with_dependency schema_name, table_name
|
86
|
+
results = @fragments.filter { |f| f.is_dependent_on? schema_name, table_name }
|
87
|
+
# remove any of these from the internal array of fragments
|
88
|
+
@fragments.filter! { |f| !f.is_dependent_on?(schema_name, table_name) }
|
89
|
+
# return the results
|
90
|
+
results
|
91
|
+
end
|
92
|
+
|
93
|
+
# Combine the fragments, and build a string representation of the migration
|
94
|
+
# using the structure templates defined in this class.
|
95
|
+
# Will raise an error if no fragments have been provided.
|
96
|
+
def content
|
97
|
+
raise NoFragmentsError if fragments.empty?
|
98
|
+
sections = []
|
99
|
+
self.class.structure_templates.each do |section|
|
100
|
+
# add the header comment if we have a migration which matches one of the
|
101
|
+
# methods in this section
|
102
|
+
if (section[:methods] & @fragments.map(&:migration_method)).any?
|
103
|
+
sections << section[:header_comment].strip
|
104
|
+
end
|
105
|
+
|
106
|
+
# iterate through this sections methods in order and look
|
107
|
+
# for any that match the migrations we have
|
108
|
+
section[:methods].each do |migration_method|
|
109
|
+
# if we have any migration fragments for this method then add them
|
110
|
+
@fragments.filter { |f| f.migration_method == migration_method }.each do |fragment|
|
111
|
+
sections << fragment.to_s
|
112
|
+
sections << ""
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
sections.join("\n").strip
|
117
|
+
end
|
118
|
+
|
119
|
+
# Using the migration fragments, generate a friendly/descriptive name for the migration.
|
120
|
+
# Will raise an error if no fragments have been provided.
|
121
|
+
def name
|
122
|
+
raise NoFragmentsError if fragments.empty?
|
123
|
+
|
124
|
+
if fragments_for_method? :create_schema
|
125
|
+
"create_#{first_fragment_using_migration_method(:create_schema).schema_name}_schema".to_sym
|
126
|
+
|
127
|
+
elsif fragments_for_method? :drop_schema
|
128
|
+
"drop_#{first_fragment_using_migration_method(:drop_schema).schema_name}_schema".to_sym
|
129
|
+
|
130
|
+
elsif fragments_for_method? :create_table
|
131
|
+
"create_#{first_fragment_using_migration_method(:create_table).table_name}".to_sym
|
132
|
+
|
133
|
+
elsif fragments_for_method? :drop_table
|
134
|
+
"drop_#{first_fragment_using_migration_method(:drop_table).table_name}".to_sym
|
135
|
+
|
136
|
+
elsif all_fragments_for_method? [:create_function]
|
137
|
+
"create_function_#{@fragments.find { |s| s.migration_method == :create_function }&.object_name}".to_sym
|
138
|
+
|
139
|
+
elsif all_fragments_for_method? [:create_function, :update_function, :drop_function, :set_function_comment, :remove_function_comment]
|
140
|
+
:schema_functions
|
141
|
+
|
142
|
+
elsif @fragments.first&.table_name
|
143
|
+
"changes_for_#{@fragments.first&.table_name}".to_sym
|
144
|
+
|
145
|
+
else
|
146
|
+
:changes
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
def supported_migration_method? method_name
|
153
|
+
self.class.structure_templates.map { |s| s[:methods] }.flatten.include? method_name
|
154
|
+
end
|
155
|
+
|
156
|
+
def fragments_for_method? migration_method
|
157
|
+
@fragments.map(&:migration_method).include? migration_method
|
158
|
+
end
|
159
|
+
|
160
|
+
def first_fragment_using_migration_method migration_method
|
161
|
+
fragment = @fragments.find(&:migration_method)
|
162
|
+
if fragment.nil?
|
163
|
+
raise SectionNotFoundError, "No fragment of type #{migration_method} found"
|
164
|
+
end
|
165
|
+
fragment
|
166
|
+
end
|
167
|
+
|
168
|
+
# return true if the current migration only has the provided content types and comments
|
169
|
+
def all_fragments_for_method? migration_methods
|
170
|
+
(@fragments.map(&:migration_method) - migration_methods - [:comment]).empty?
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# TSort is a module included in the Ruby standard library for
|
2
|
+
# executing topological sorts. We use it here to sort the migration
|
3
|
+
# fragments so that they are executed in the correct order (i.e. tables
|
4
|
+
# which have foreign keys are created after the tables they point to).
|
5
|
+
require "tsort"
|
6
|
+
|
7
|
+
module DynamicMigrations
|
8
|
+
module Postgres
|
9
|
+
class Generator
|
10
|
+
class MigrationDependencySorter < Hash
|
11
|
+
include TSort
|
12
|
+
|
13
|
+
alias_method :tsort_each_node, :each_key
|
14
|
+
|
15
|
+
def tsort_each_child(node, &block)
|
16
|
+
fetch(node).each(&block)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -22,15 +22,25 @@ module DynamicMigrations
|
|
22
22
|
|
23
23
|
options_syntax = options.map { |k, v| "#{k}: #{v}" }.join(", ")
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
add_fragment schema: primary_key.table.schema,
|
26
|
+
table: primary_key.table,
|
27
|
+
migration_method: :add_primary_key,
|
28
|
+
object: primary_key,
|
29
|
+
code_comment: code_comment,
|
30
|
+
migration: <<~RUBY
|
31
|
+
add_primary_key :#{primary_key.table.name}, #{column_names}, #{options_syntax}
|
32
|
+
RUBY
|
28
33
|
end
|
29
34
|
|
30
35
|
def remove_primary_key primary_key, code_comment = nil
|
31
|
-
|
32
|
-
|
33
|
-
|
36
|
+
add_fragment schema: primary_key.table.schema,
|
37
|
+
table: primary_key.table,
|
38
|
+
migration_method: :remove_primary_key,
|
39
|
+
object: primary_key,
|
40
|
+
code_comment: code_comment,
|
41
|
+
migration: <<~RUBY
|
42
|
+
remove_primary_key :#{primary_key.table.name}, :#{primary_key.name}
|
43
|
+
RUBY
|
34
44
|
end
|
35
45
|
|
36
46
|
def recreate_primary_key original_primary_key, updated_primary_key
|