dynamic_migrations 3.3.1 → 3.4.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 +7 -0
- data/lib/dynamic_migrations/active_record/migrators/enum.rb +44 -0
- data/lib/dynamic_migrations/active_record/migrators.rb +1 -0
- data/lib/dynamic_migrations/postgres/generator/database_migration.rb +14 -0
- data/lib/dynamic_migrations/postgres/generator/enum.rb +75 -0
- data/lib/dynamic_migrations/postgres/generator/extension.rb +27 -0
- data/lib/dynamic_migrations/postgres/generator/migration.rb +50 -19
- data/lib/dynamic_migrations/postgres/generator/schema_migration.rb +8 -0
- data/lib/dynamic_migrations/postgres/generator/table_migration.rb +1 -16
- data/lib/dynamic_migrations/postgres/generator.rb +25 -5
- data/lib/dynamic_migrations/postgres/server/database/configured_extensions.rb +40 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/extensions.rb +30 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/enums.rb +73 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas.rb +3 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations.rb +10 -2
- data/lib/dynamic_migrations/postgres/server/database/differences.rb +55 -3
- data/lib/dynamic_migrations/postgres/server/database/enums_loader.rb +40 -0
- data/lib/dynamic_migrations/postgres/server/database/extensions_loader.rb +26 -0
- data/lib/dynamic_migrations/postgres/server/database/loaded_extensions.rb +40 -0
- data/lib/dynamic_migrations/postgres/server/database/loaded_schemas_builder.rb +13 -1
- data/lib/dynamic_migrations/postgres/server/database/schema/enum.rb +60 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/enums.rb +63 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/function.rb +1 -1
- data/lib/dynamic_migrations/postgres/server/database/schema.rb +2 -0
- data/lib/dynamic_migrations/postgres/server/database/structure_loader.rb +1 -1
- data/lib/dynamic_migrations/postgres/server/database.rb +6 -0
- data/lib/dynamic_migrations/version.rb +1 -1
- data/lib/dynamic_migrations.rb +12 -0
- metadata +14 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4175e35ddf2a941304c9efec0400c7ed6d933bf982d3744eb45f2891d6806ec6
|
|
4
|
+
data.tar.gz: c78c493bf1660d8b2eb36fe355a07869b8ef2fdbc4a05527da51e27b56dcfa2e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f4e13bc988a286385fa6e39b4cbf5d001674cec8482ee9cb4680d34fe9b3a82fc869dccbef8c31527f3f23a4230796cc07b4559bd90c35373b3865877328878c
|
|
7
|
+
data.tar.gz: 73a51e5ae774cd41863e67c2f5cf7f541beaeddbf6b027d81637a6926542d267fb0ca34e790b86b206786668cf2fc3466242a6347871ed552f739aa2a7a8baf8
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.4.0](https://github.com/craigulliott/dynamic_migrations/compare/v3.3.1...v3.4.0) (2023-08-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* adding support for enums and extensions ([6e00d5f](https://github.com/craigulliott/dynamic_migrations/commit/6e00d5fc726e2a1bbeb282477c8bca92b94462cf))
|
|
9
|
+
|
|
3
10
|
## [3.3.1](https://github.com/craigulliott/dynamic_migrations/compare/v3.3.0...v3.3.1) (2023-08-18)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module DynamicMigrations
|
|
2
|
+
module ActiveRecord
|
|
3
|
+
module Migrators
|
|
4
|
+
module Enum
|
|
5
|
+
# create a postgres enum
|
|
6
|
+
def create_enum enum_name, values
|
|
7
|
+
# schema_name was not provided to this method, it comes from the migration class
|
|
8
|
+
execute <<~SQL
|
|
9
|
+
CREATE TYPE #{schema_name}.#{enum_name} as ENUM ('#{values.join("','")}');
|
|
10
|
+
SQL
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# add vaues to a given enum
|
|
14
|
+
def add_enum_values enum_name, values
|
|
15
|
+
sqls = values.map do |value|
|
|
16
|
+
"ALTER TYPE #{schema_name}.#{enum_name} ADD ATTRIBUTE '#{value}';"
|
|
17
|
+
end
|
|
18
|
+
execute sqls.join("\n")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# remove a enum from the schema
|
|
22
|
+
def drop_enum enum_name
|
|
23
|
+
execute <<~SQL
|
|
24
|
+
DROP TYPE #{schema_name}.#{enum_name};
|
|
25
|
+
SQL
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# add a comment to a enum
|
|
29
|
+
def set_enum_comment enum_name, comment
|
|
30
|
+
execute <<~SQL
|
|
31
|
+
COMMENT ON TYPE #{schema_name}.#{enum_name} IS '#{quote comment}';
|
|
32
|
+
SQL
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# remove the comment from a enum
|
|
36
|
+
def remove_enum_comment enum_name
|
|
37
|
+
execute <<~SQL
|
|
38
|
+
COMMENT ON TYPE #{schema_name}.#{enum_name} IS null;
|
|
39
|
+
SQL
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module DynamicMigrations
|
|
2
|
+
module Postgres
|
|
3
|
+
class Generator
|
|
4
|
+
class DatabaseMigration < Migration
|
|
5
|
+
# these sections are in order for which they will appear in a migration,
|
|
6
|
+
# note that removals come before additions, and that the order here optomizes
|
|
7
|
+
# for dependencies (i.e. columns have to be created before indexes are added and
|
|
8
|
+
# triggers are removed before functions are dropped)
|
|
9
|
+
add_structure_template [:create_extension], "Create Extension"
|
|
10
|
+
add_structure_template [:drop_extension], "Drop Extension"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module DynamicMigrations
|
|
2
|
+
module Postgres
|
|
3
|
+
class Generator
|
|
4
|
+
module Enum
|
|
5
|
+
class UnremovableEnumValuesError < StandardError
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def create_enum enum, code_comment = nil
|
|
9
|
+
add_fragment schema: enum.schema,
|
|
10
|
+
migration_method: :create_enum,
|
|
11
|
+
object: enum,
|
|
12
|
+
code_comment: code_comment,
|
|
13
|
+
migration: <<~RUBY
|
|
14
|
+
create_enum :#{enum.name}, [
|
|
15
|
+
:#{enum.values.join(",\n :")}
|
|
16
|
+
]
|
|
17
|
+
RUBY
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def update_enum original_enum, updated_enum, code_comment = nil
|
|
21
|
+
added_values = updated_enum.values - original_enum.values
|
|
22
|
+
removed_values = original_enum.values - updated_enum.values
|
|
23
|
+
|
|
24
|
+
if removed_values.any?
|
|
25
|
+
raise UnremovableEnumValuesError, "You can not remove enum values from postgres. Tring to remove '#{removed_values.join("', ")}'"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
add_fragment schema: updated_enum.schema,
|
|
29
|
+
migration_method: :add_enum_values,
|
|
30
|
+
object: updated_enum,
|
|
31
|
+
code_comment: code_comment,
|
|
32
|
+
migration: <<~RUBY
|
|
33
|
+
add_enum_values :#{updated_enum.name}, [
|
|
34
|
+
:#{added_values.join(",\n :")}
|
|
35
|
+
]
|
|
36
|
+
RUBY
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def drop_enum enum, code_comment = nil
|
|
40
|
+
add_fragment schema: enum.schema,
|
|
41
|
+
migration_method: :drop_enum,
|
|
42
|
+
object: enum,
|
|
43
|
+
code_comment: code_comment,
|
|
44
|
+
migration: <<~RUBY
|
|
45
|
+
drop_enum :#{enum.name}
|
|
46
|
+
RUBY
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# add a comment to a enum
|
|
50
|
+
def set_enum_comment enum, code_comment = nil
|
|
51
|
+
add_fragment schema: enum.schema,
|
|
52
|
+
migration_method: :set_enum_comment,
|
|
53
|
+
object: enum,
|
|
54
|
+
code_comment: code_comment,
|
|
55
|
+
migration: <<~RUBY
|
|
56
|
+
set_enum_comment :#{enum.name}, <<~COMMENT
|
|
57
|
+
#{indent enum.description || ""}
|
|
58
|
+
COMMENT
|
|
59
|
+
RUBY
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# remove the comment from a enum
|
|
63
|
+
def remove_enum_comment enum, code_comment = nil
|
|
64
|
+
add_fragment schema: enum.schema,
|
|
65
|
+
migration_method: :remove_enum_comment,
|
|
66
|
+
object: enum,
|
|
67
|
+
code_comment: code_comment,
|
|
68
|
+
migration: <<~RUBY
|
|
69
|
+
remove_enum_comment :#{enum.name}
|
|
70
|
+
RUBY
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module DynamicMigrations
|
|
2
|
+
module Postgres
|
|
3
|
+
class Generator
|
|
4
|
+
module Extension
|
|
5
|
+
def create_extension extension_name, code_comment = nil
|
|
6
|
+
# no table or schema name for this fragment (it is executed at the database level)
|
|
7
|
+
add_fragment migration_method: :create_extension,
|
|
8
|
+
object: extension_name,
|
|
9
|
+
code_comment: code_comment,
|
|
10
|
+
migration: <<~RUBY
|
|
11
|
+
create_extension :#{extension_name}
|
|
12
|
+
RUBY
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def drop_extension extension_name, code_comment = nil
|
|
16
|
+
# no table or schema name for this fragment (it is executed at the database level)
|
|
17
|
+
add_fragment migration_method: :drop_extension,
|
|
18
|
+
object: extension_name,
|
|
19
|
+
code_comment: code_comment,
|
|
20
|
+
migration: <<~RUBY
|
|
21
|
+
drop_extension :#{extension_name}
|
|
22
|
+
RUBY
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -2,9 +2,6 @@ module DynamicMigrations
|
|
|
2
2
|
module Postgres
|
|
3
3
|
class Generator
|
|
4
4
|
class Migration
|
|
5
|
-
class UnexpectedSchemaError < StandardError
|
|
6
|
-
end
|
|
7
|
-
|
|
8
5
|
class SectionNotFoundError < StandardError
|
|
9
6
|
end
|
|
10
7
|
|
|
@@ -17,6 +14,29 @@ module DynamicMigrations
|
|
|
17
14
|
class NoFragmentsError < StandardError
|
|
18
15
|
end
|
|
19
16
|
|
|
17
|
+
class MissingRequiredTableName < StandardError
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class MissingRequiredSchemaName < StandardError
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class UnexpectedTableError < StandardError
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class UnexpectedSchemaError < StandardError
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
attr_reader :table_name
|
|
30
|
+
attr_reader :schema_name
|
|
31
|
+
attr_reader :fragments
|
|
32
|
+
|
|
33
|
+
# schema_name and table_name can be nil
|
|
34
|
+
def initialize schema_name = nil, table_name = nil
|
|
35
|
+
@schema_name = schema_name
|
|
36
|
+
@table_name = table_name
|
|
37
|
+
@fragments = []
|
|
38
|
+
end
|
|
39
|
+
|
|
20
40
|
# Defines a new section in the migration file, this is used to group
|
|
21
41
|
# migration fragments of the provided method names together under the
|
|
22
42
|
# provided header
|
|
@@ -47,25 +67,27 @@ module DynamicMigrations
|
|
|
47
67
|
@structure_templates = []
|
|
48
68
|
end
|
|
49
69
|
|
|
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
70
|
# Add a migration fragment to this migration, if the migration is not
|
|
59
71
|
# configured (via a structure template) to handle the method_name of the
|
|
60
72
|
# fragment, then am error is raised. An error will also be raised if the
|
|
61
73
|
# migration belongs to a different schema than the provided fragment.
|
|
62
74
|
def add_fragment fragment
|
|
63
|
-
raise UnexpectedSchemaError unless @schema_name == fragment.schema_name
|
|
64
|
-
|
|
65
75
|
unless supported_migration_method? fragment.migration_method
|
|
66
76
|
raise UnexpectedMigrationMethodNameError, "Expected method to be a valid migrator method, got `#{fragment.migration_method}`"
|
|
67
77
|
end
|
|
68
78
|
|
|
79
|
+
# confirm the fragment is for this schema (even if both
|
|
80
|
+
# these values are nil/there is no schema)
|
|
81
|
+
unless @schema_name == fragment.schema_name
|
|
82
|
+
raise UnexpectedSchemaError, "Fragment is for schema `#{fragment.schema_name || "nil"}` but migration is for schema `#{@schema_name || "nil"}`"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# confirm this fragment is for this table, this works for database and schame
|
|
86
|
+
# migrations to, as all values should be nil
|
|
87
|
+
unless @table_name == fragment.table_name
|
|
88
|
+
raise UnexpectedTableError, "Fragment is for table `#{fragment.table_name || "nil"}` but migration is for table `#{@table_name || "nil"}`"
|
|
89
|
+
end
|
|
90
|
+
|
|
69
91
|
@fragments << fragment
|
|
70
92
|
|
|
71
93
|
fragment
|
|
@@ -122,25 +144,34 @@ module DynamicMigrations
|
|
|
122
144
|
raise NoFragmentsError if fragments.empty?
|
|
123
145
|
|
|
124
146
|
if fragments_for_method? :create_schema
|
|
125
|
-
"create_#{first_fragment_using_migration_method(:create_schema).schema_name}_schema"
|
|
147
|
+
:"create_#{first_fragment_using_migration_method(:create_schema).schema_name}_schema"
|
|
126
148
|
|
|
127
149
|
elsif fragments_for_method? :drop_schema
|
|
128
|
-
"drop_#{first_fragment_using_migration_method(:drop_schema).schema_name}_schema"
|
|
150
|
+
:"drop_#{first_fragment_using_migration_method(:drop_schema).schema_name}_schema"
|
|
129
151
|
|
|
130
152
|
elsif fragments_for_method? :create_table
|
|
131
|
-
"create_#{first_fragment_using_migration_method(:create_table).table_name}"
|
|
153
|
+
:"create_#{first_fragment_using_migration_method(:create_table).table_name}"
|
|
132
154
|
|
|
133
155
|
elsif fragments_for_method? :drop_table
|
|
134
|
-
"drop_#{first_fragment_using_migration_method(:drop_table).table_name}"
|
|
156
|
+
:"drop_#{first_fragment_using_migration_method(:drop_table).table_name}"
|
|
135
157
|
|
|
136
158
|
elsif all_fragments_for_method? [:create_function]
|
|
137
|
-
"create_function_#{@fragments.find { |s| s.migration_method == :create_function }&.object_name}"
|
|
159
|
+
:"create_function_#{@fragments.find { |s| s.migration_method == :create_function }&.object_name}"
|
|
138
160
|
|
|
139
161
|
elsif all_fragments_for_method? [:create_function, :update_function, :drop_function, :set_function_comment, :remove_function_comment]
|
|
140
162
|
:schema_functions
|
|
141
163
|
|
|
164
|
+
elsif all_fragments_for_method? [:create_enum, :add_enum_values, :drop_enum, :set_enum_comment, :remove_enum_comment]
|
|
165
|
+
:enums
|
|
166
|
+
|
|
167
|
+
elsif all_fragments_for_method? [:create_extension]
|
|
168
|
+
(@fragments.count > 1) ? :":create_extensions" : :"create_#{fragments.first&.object_name}_extension"
|
|
169
|
+
|
|
170
|
+
elsif all_fragments_for_method? [:drop_extension]
|
|
171
|
+
(@fragments.count > 1) ? :":drop_extensions" : :"drop_#{fragments.first&.object_name}_extension"
|
|
172
|
+
|
|
142
173
|
elsif @fragments.first&.table_name
|
|
143
|
-
"changes_for_#{@fragments.first&.table_name}"
|
|
174
|
+
:"changes_for_#{@fragments.first&.table_name}"
|
|
144
175
|
|
|
145
176
|
else
|
|
146
177
|
:changes
|
|
@@ -7,10 +7,18 @@ module DynamicMigrations
|
|
|
7
7
|
# for dependencies (i.e. columns have to be created before indexes are added and
|
|
8
8
|
# triggers are removed before functions are dropped)
|
|
9
9
|
add_structure_template [:remove_function_comment, :drop_function], "Remove Functions"
|
|
10
|
+
add_structure_template [:remove_enum_comment, :drop_enum], "Drop Enums"
|
|
10
11
|
add_structure_template [:drop_schema], "Drop this schema"
|
|
12
|
+
add_structure_template [:create_enum, :add_enum_values, :set_enum_comment], "Enums"
|
|
11
13
|
add_structure_template [:create_schema], "Create this schema"
|
|
12
14
|
add_structure_template [:create_function], "Functions"
|
|
13
15
|
add_structure_template [:update_function, :set_function_comment], "Update Functions"
|
|
16
|
+
add_structure_template [:create_extension, :drop_extension], "Extensions"
|
|
17
|
+
|
|
18
|
+
def initialize schema_name
|
|
19
|
+
raise MissingRequiredSchemaName unless schema_name
|
|
20
|
+
super
|
|
21
|
+
end
|
|
14
22
|
end
|
|
15
23
|
end
|
|
16
24
|
end
|
|
@@ -2,12 +2,6 @@ module DynamicMigrations
|
|
|
2
2
|
module Postgres
|
|
3
3
|
class Generator
|
|
4
4
|
class TableMigration < Migration
|
|
5
|
-
class UnexpectedTableError < StandardError
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
class MissingRequiredTableName < StandardError
|
|
9
|
-
end
|
|
10
|
-
|
|
11
5
|
# these sections are in order for which they will appear in a migration,
|
|
12
6
|
# note that removals come before additions, and that the order here optomizes
|
|
13
7
|
# for dependencies (i.e. columns have to be created before indexes are added and
|
|
@@ -31,18 +25,9 @@ module DynamicMigrations
|
|
|
31
25
|
add_structure_template [:add_trigger, :set_trigger_comment], "Triggers"
|
|
32
26
|
add_structure_template [:update_function, :set_function_comment], "Update Functions"
|
|
33
27
|
|
|
34
|
-
attr_accessor :table_name
|
|
35
|
-
|
|
36
28
|
def initialize schema_name, table_name
|
|
29
|
+
raise MissingRequiredSchemaName unless schema_name
|
|
37
30
|
raise MissingRequiredTableName unless table_name
|
|
38
|
-
super schema_name
|
|
39
|
-
@table_name = table_name
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def add_fragment fragment
|
|
43
|
-
unless @table_name == fragment.table_name
|
|
44
|
-
raise UnexpectedTableError, "Frgment is for table `#{fragment.table_name}` but migration is for table `#{@table_name}`"
|
|
45
|
-
end
|
|
46
31
|
super
|
|
47
32
|
end
|
|
48
33
|
end
|
|
@@ -16,6 +16,9 @@ module DynamicMigrations
|
|
|
16
16
|
class TableMigrationNotFound < StandardError
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
class UnprocessableFragmentError < StandardError
|
|
20
|
+
end
|
|
21
|
+
|
|
19
22
|
include Schema
|
|
20
23
|
include Table
|
|
21
24
|
include Column
|
|
@@ -26,6 +29,8 @@ module DynamicMigrations
|
|
|
26
29
|
include Validation
|
|
27
30
|
include Function
|
|
28
31
|
include Trigger
|
|
32
|
+
include Enum
|
|
33
|
+
include Extension
|
|
29
34
|
|
|
30
35
|
def initialize
|
|
31
36
|
@fragments = []
|
|
@@ -36,6 +41,9 @@ module DynamicMigrations
|
|
|
36
41
|
# a hash to hold the generated migrations orgnized by their schema and table
|
|
37
42
|
# this makes it easier and faster to work with them within this method
|
|
38
43
|
database_migrations = {}
|
|
44
|
+
# the database_specific_migration is for migrations which dont belong
|
|
45
|
+
# within a specific schema
|
|
46
|
+
database_specific_migration = DatabaseMigration.new
|
|
39
47
|
|
|
40
48
|
# Process each fragment, and organize them into migrations. We create a shared
|
|
41
49
|
# Migration for each table, and a single shared migration for any schema migrations
|
|
@@ -54,15 +62,22 @@ module DynamicMigrations
|
|
|
54
62
|
table_name = fragment.table_name
|
|
55
63
|
# If we have a table name, then add the migration fragment to a
|
|
56
64
|
# TableMigration which holds all of the migrations for this table
|
|
57
|
-
if table_name
|
|
65
|
+
if table_name && schema_name
|
|
58
66
|
table_migration = schema_migrations[:table_migrations][table_name] ||= TableMigration.new(schema_name, table_name)
|
|
59
67
|
table_migration.add_fragment fragment
|
|
60
68
|
|
|
61
|
-
# migration fragments which do not belong to a specific table are added
|
|
69
|
+
# migration fragments which do have a schema, but do not belong to a specific table are added
|
|
62
70
|
# to a dedicated SchemaMigration object
|
|
63
|
-
|
|
71
|
+
elsif schema_name && table_name.nil?
|
|
64
72
|
schema_migration = schema_migrations[:schema_migration] ||= SchemaMigration.new(schema_name)
|
|
65
73
|
schema_migration.add_fragment fragment
|
|
74
|
+
|
|
75
|
+
# migrations with no schema or table, are added to a database
|
|
76
|
+
# migration (these re really just creating/dropping extensions)
|
|
77
|
+
elsif schema_name.nil? && table_name.nil?
|
|
78
|
+
database_specific_migration.add_fragment fragment
|
|
79
|
+
else
|
|
80
|
+
raise UnprocessableFragmentError
|
|
66
81
|
end
|
|
67
82
|
end
|
|
68
83
|
|
|
@@ -158,6 +173,11 @@ module DynamicMigrations
|
|
|
158
173
|
# the order is determined by their dependencies
|
|
159
174
|
final_migrations = dependency_sorter.tsort
|
|
160
175
|
|
|
176
|
+
# if any database only migrations exist, then add them to the from of the array here
|
|
177
|
+
if database_specific_migration.fragments.any?
|
|
178
|
+
final_migrations.unshift database_specific_migration
|
|
179
|
+
end
|
|
180
|
+
|
|
161
181
|
# return the final migrations in the expected format
|
|
162
182
|
final_migrations.map do |migration|
|
|
163
183
|
{
|
|
@@ -200,11 +220,11 @@ module DynamicMigrations
|
|
|
200
220
|
@dep[node].each(&block)
|
|
201
221
|
end
|
|
202
222
|
|
|
203
|
-
def add_fragment
|
|
223
|
+
def add_fragment migration_method:, object:, migration:, schema: nil, table: nil, code_comment: nil, dependent_table: nil
|
|
204
224
|
# Remove any empty lines and whitespace from the beginning or the end of the migration and then
|
|
205
225
|
# strip any empty lines witin the migration (remove the whitespace from them, not delete them).
|
|
206
226
|
final_migration = strip_empty_lines(migration).strip
|
|
207
|
-
fragment = Fragment.new(schema
|
|
227
|
+
fragment = Fragment.new(schema&.name, table&.name, migration_method, object.name, code_comment, final_migration)
|
|
208
228
|
if dependent_table
|
|
209
229
|
fragment.set_dependent_table dependent_table.schema.name, dependent_table.name
|
|
210
230
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DynamicMigrations
|
|
4
|
+
module Postgres
|
|
5
|
+
class Server
|
|
6
|
+
class Database
|
|
7
|
+
module ConfiguredExtensions
|
|
8
|
+
class ConfiguredExtensionAlreadyExistsError < StandardError
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# adds a new configured extension for this database
|
|
12
|
+
def add_configured_extension extension_name
|
|
13
|
+
raise ExpectedSymbolError, extension_name unless extension_name.is_a? Symbol
|
|
14
|
+
if has_configured_extension? extension_name
|
|
15
|
+
raise(ConfiguredExtensionAlreadyExistsError, "Configured extension #{extension_name} already exists")
|
|
16
|
+
end
|
|
17
|
+
# sort the hash so that the extensions are in alphabetical order by name
|
|
18
|
+
@configured_extensions[extension_name] = true
|
|
19
|
+
sorted_extensions = {}
|
|
20
|
+
@configured_extensions.keys.sort.each do |extension_name|
|
|
21
|
+
sorted_extensions[extension_name] = true
|
|
22
|
+
end
|
|
23
|
+
@configured_extensions = sorted_extensions
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# returns true if this table has a configured extension with the provided name, otherwise false
|
|
27
|
+
def has_configured_extension? extension_name
|
|
28
|
+
raise ExpectedSymbolError, extension_name unless extension_name.is_a? Symbol
|
|
29
|
+
@configured_extensions.key? extension_name
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# returns an array of this tables configured extensions
|
|
33
|
+
def configured_extensions
|
|
34
|
+
@configured_extensions.keys
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DynamicMigrations
|
|
4
|
+
module Postgres
|
|
5
|
+
class Server
|
|
6
|
+
class Database
|
|
7
|
+
class Differences
|
|
8
|
+
class ToMigrations
|
|
9
|
+
module Extensions
|
|
10
|
+
def process_extension extension_name, configuration_extension, database_extension
|
|
11
|
+
# if the extension exists in the configuration but not in the database
|
|
12
|
+
# then we have to create it
|
|
13
|
+
if configuration_extension[:exists] == true && database_extension[:exists] == false
|
|
14
|
+
# a migration to create the extension
|
|
15
|
+
@generator.create_extension extension_name
|
|
16
|
+
|
|
17
|
+
# if the extension exists in the database but not in the configuration
|
|
18
|
+
# then we need to delete it
|
|
19
|
+
elsif configuration_extension[:exists] == false && database_extension[:exists] == true
|
|
20
|
+
# a migration to drop the extension
|
|
21
|
+
@generator.drop_extension extension_name
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/enums.rb
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DynamicMigrations
|
|
4
|
+
module Postgres
|
|
5
|
+
class Server
|
|
6
|
+
class Database
|
|
7
|
+
class Differences
|
|
8
|
+
class ToMigrations
|
|
9
|
+
module Schemas
|
|
10
|
+
module Enums
|
|
11
|
+
def process_enums schema_name, configuration_enums, database_enums
|
|
12
|
+
# process all the enums
|
|
13
|
+
enum_names = (configuration_enums.keys + database_enums.keys).uniq
|
|
14
|
+
enum_names.each do |enum_name|
|
|
15
|
+
process_enum schema_name, enum_name, configuration_enums[enum_name] || {}, database_enums[enum_name] || {}
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def process_enum schema_name, enum_name, configuration_enum, database_enum
|
|
20
|
+
# If the enum exists in the configuration but not in the database
|
|
21
|
+
# then we have to create it.
|
|
22
|
+
if configuration_enum[:exists] == true && database_enum[:exists] == false
|
|
23
|
+
# a migration to create the enum
|
|
24
|
+
enum = @database.configured_schema(schema_name).enum(enum_name)
|
|
25
|
+
@generator.create_enum enum
|
|
26
|
+
# optionally add the description
|
|
27
|
+
if enum.has_description?
|
|
28
|
+
@generator.set_enum_comment enum
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# If the schema exists in the database but not in the configuration
|
|
32
|
+
# then we need to delete it.
|
|
33
|
+
elsif configuration_enum[:exists] == false && database_enum[:exists] == true
|
|
34
|
+
# a migration to create the enum
|
|
35
|
+
enum = @database.loaded_schema(schema_name).enum(enum_name)
|
|
36
|
+
@generator.drop_enum enum
|
|
37
|
+
|
|
38
|
+
# If the enum exists in both the configuration and database representations
|
|
39
|
+
# but the values is different then we need to update the values.
|
|
40
|
+
elsif configuration_enum[:values][:matches] == false
|
|
41
|
+
original_enum = @database.loaded_schema(schema_name).enum(enum_name)
|
|
42
|
+
updated_enum = @database.configured_schema(schema_name).enum(enum_name)
|
|
43
|
+
@generator.update_enum original_enum, updated_enum
|
|
44
|
+
# does the description also need to be updated
|
|
45
|
+
if configuration_enum[:description][:matches] == false
|
|
46
|
+
# if the description was removed
|
|
47
|
+
if configuration_enum[:description].nil?
|
|
48
|
+
@generator.remove_enum_comment updated_enum
|
|
49
|
+
else
|
|
50
|
+
@generator.set_enum_comment updated_enum
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# If the enum exists in both the configuration and database representations
|
|
55
|
+
# but the description is different then we need to update the description.
|
|
56
|
+
elsif configuration_enum[:description][:matches] == false
|
|
57
|
+
enum = @database.configured_schema(schema_name).enum(enum_name)
|
|
58
|
+
# if the description was removed
|
|
59
|
+
if configuration_enum[:description].nil?
|
|
60
|
+
@generator.remove_enum_comment enum
|
|
61
|
+
else
|
|
62
|
+
@generator.set_enum_comment enum
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -18,6 +18,7 @@ module DynamicMigrations
|
|
|
18
18
|
# we process the tables and functions after we create the schema
|
|
19
19
|
# otherwise the schemas objects will not be able to be created
|
|
20
20
|
process_functions schema_name, configuration_schema[:functions], {}
|
|
21
|
+
process_enums schema_name, configuration_schema[:enums], {}
|
|
21
22
|
process_tables schema_name, configuration_schema[:tables], {}
|
|
22
23
|
|
|
23
24
|
# if the schema exists in the database but not in the configuration
|
|
@@ -26,6 +27,7 @@ module DynamicMigrations
|
|
|
26
27
|
# we process the tables and functions before we drop the schema
|
|
27
28
|
# as this will drop any dependencies on the schema
|
|
28
29
|
process_functions schema_name, {}, database_schema[:functions]
|
|
30
|
+
process_enums schema_name, {}, database_schema[:enums]
|
|
29
31
|
process_tables schema_name, {}, database_schema[:tables]
|
|
30
32
|
|
|
31
33
|
# a migration to drop the schema
|
|
@@ -36,6 +38,7 @@ module DynamicMigrations
|
|
|
36
38
|
# then we just need to process the tables and functions
|
|
37
39
|
else
|
|
38
40
|
process_functions schema_name, configuration_schema[:functions], database_schema[:functions]
|
|
41
|
+
process_enums schema_name, configuration_schema[:enums], database_schema[:enums]
|
|
39
42
|
process_tables schema_name, configuration_schema[:tables], database_schema[:tables]
|
|
40
43
|
end
|
|
41
44
|
end
|
|
@@ -12,8 +12,10 @@ module DynamicMigrations
|
|
|
12
12
|
class UnexpectedDifferencesObjectError < StandardError
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
include Extensions
|
|
15
16
|
include Schemas
|
|
16
17
|
include Schemas::Functions
|
|
18
|
+
include Schemas::Enums
|
|
17
19
|
include Schemas::Tables
|
|
18
20
|
include Schemas::Tables::Columns
|
|
19
21
|
include Schemas::Tables::ForeignKeyConstraints
|
|
@@ -35,11 +37,17 @@ module DynamicMigrations
|
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
def migrations
|
|
40
|
+
# process all the extensions
|
|
41
|
+
extension_names = differences[:configuration][:extensions].keys
|
|
42
|
+
extension_names.each do |extension_name|
|
|
43
|
+
process_extension extension_name, differences[:configuration][:extensions][extension_name], differences[:database][:extensions][extension_name]
|
|
44
|
+
end
|
|
45
|
+
|
|
38
46
|
# process all the schemas (we can fetch the schema names from either the
|
|
39
47
|
# configuration or the database object)
|
|
40
|
-
schema_names = differences[:configuration].keys
|
|
48
|
+
schema_names = differences[:configuration][:schemas].keys
|
|
41
49
|
schema_names.each do |schema_name|
|
|
42
|
-
process_schema schema_name, differences[:configuration][schema_name], differences[:database][schema_name]
|
|
50
|
+
process_schema schema_name, differences[:configuration][:schemas][schema_name], differences[:database][:schemas][schema_name]
|
|
43
51
|
end
|
|
44
52
|
|
|
45
53
|
# return the migrations organized by schema
|
|
@@ -32,11 +32,38 @@ module DynamicMigrations
|
|
|
32
32
|
# versions of the current database
|
|
33
33
|
def to_h
|
|
34
34
|
{
|
|
35
|
-
configuration:
|
|
36
|
-
|
|
35
|
+
configuration: {
|
|
36
|
+
schemas: self.class.compare_schemas(@database.configured_schemas_hash, @database.loaded_schemas_hash),
|
|
37
|
+
extensions: self.class.compare_extensions(@database.configured_extensions, @database.loaded_extensions)
|
|
38
|
+
},
|
|
39
|
+
database: {
|
|
40
|
+
schemas: self.class.compare_schemas(@database.loaded_schemas_hash, @database.configured_schemas_hash),
|
|
41
|
+
extensions: self.class.compare_extensions(@database.loaded_extensions, @database.configured_extensions)
|
|
42
|
+
}
|
|
37
43
|
}
|
|
38
44
|
end
|
|
39
45
|
|
|
46
|
+
def self.compare_extensions extensions, comparison_extensions
|
|
47
|
+
result = {}
|
|
48
|
+
# the extensions
|
|
49
|
+
extensions.each do |extension_name|
|
|
50
|
+
# compare this extension to the equivilent in the comparison list
|
|
51
|
+
# note that the comparison may be nil
|
|
52
|
+
result[extension_name] = {
|
|
53
|
+
exists: true
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
# look for any in the comparison list which were not in the base list
|
|
57
|
+
comparison_extensions.each do |extension_name|
|
|
58
|
+
unless result.key? extension_name
|
|
59
|
+
result[extension_name] = {
|
|
60
|
+
exists: false
|
|
61
|
+
}
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
result
|
|
65
|
+
end
|
|
66
|
+
|
|
40
67
|
def self.compare_schemas schemas, comparison_schemas
|
|
41
68
|
result = {}
|
|
42
69
|
# the base schemas
|
|
@@ -63,10 +90,12 @@ module DynamicMigrations
|
|
|
63
90
|
|
|
64
91
|
comparison_tables = comparison_schema.nil? ? {} : comparison_schema.tables_hash
|
|
65
92
|
comparison_functions = comparison_schema.nil? ? {} : comparison_schema.functions_hash
|
|
93
|
+
comparison_enums = comparison_schema.nil? ? {} : comparison_schema.enums_hash
|
|
66
94
|
{
|
|
67
95
|
exists: true,
|
|
68
96
|
tables: compare_tables(schema.tables_hash, comparison_tables),
|
|
69
|
-
functions: compare_functions(schema.functions_hash, comparison_functions)
|
|
97
|
+
functions: compare_functions(schema.functions_hash, comparison_functions),
|
|
98
|
+
enums: compare_enums(schema.enums_hash, comparison_enums)
|
|
70
99
|
}
|
|
71
100
|
end
|
|
72
101
|
|
|
@@ -158,6 +187,29 @@ module DynamicMigrations
|
|
|
158
187
|
result
|
|
159
188
|
end
|
|
160
189
|
|
|
190
|
+
# compare two hash representations of a set of enums and return
|
|
191
|
+
# an object which represents the provided `enums` and any differences
|
|
192
|
+
# between it and the `comparison_enums`
|
|
193
|
+
def self.compare_enums enums, comparison_enums
|
|
194
|
+
result = {}
|
|
195
|
+
# the base enums
|
|
196
|
+
enums.each do |enum_name, enum|
|
|
197
|
+
result[enum_name] = compare_record enum, comparison_enums[enum_name], [
|
|
198
|
+
:values,
|
|
199
|
+
:description
|
|
200
|
+
]
|
|
201
|
+
end
|
|
202
|
+
# look for any in the comparison list which were not in the base list
|
|
203
|
+
comparison_enums.each do |enum_name, enum|
|
|
204
|
+
unless result.key? enum_name
|
|
205
|
+
result[enum_name] = {
|
|
206
|
+
exists: false
|
|
207
|
+
}
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
result
|
|
211
|
+
end
|
|
212
|
+
|
|
161
213
|
# compare two hash representations of a set of columns and return
|
|
162
214
|
# an object which represents the provided `columns` and any differences
|
|
163
215
|
# between it and the `comparison_columns`
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DynamicMigrations
|
|
4
|
+
module Postgres
|
|
5
|
+
class Server
|
|
6
|
+
class Database
|
|
7
|
+
module EnumsLoader
|
|
8
|
+
def fetch_enums
|
|
9
|
+
rows = connection.exec(<<~SQL)
|
|
10
|
+
SELECT
|
|
11
|
+
n.nspname AS schema_name,
|
|
12
|
+
t.typname AS enum_name,
|
|
13
|
+
e.enumlabel AS enum_value,
|
|
14
|
+
obj_description(e.enumtypid, 'pg_type') as enum_description
|
|
15
|
+
FROM pg_type t
|
|
16
|
+
JOIN pg_enum e ON t.oid = e.enumtypid
|
|
17
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
|
18
|
+
ORDER BY enumsortorder
|
|
19
|
+
SQL
|
|
20
|
+
|
|
21
|
+
schemas = {}
|
|
22
|
+
rows.each do |row|
|
|
23
|
+
schema_name = row["schema_name"].to_sym
|
|
24
|
+
enum_name = row["enum_name"].to_sym
|
|
25
|
+
enum_value = row["enum_value"].to_sym
|
|
26
|
+
|
|
27
|
+
schema = schemas[schema_name] ||= {}
|
|
28
|
+
enum = schema[enum_name] ||= {
|
|
29
|
+
values: [],
|
|
30
|
+
description: row["enum_description"]
|
|
31
|
+
}
|
|
32
|
+
enum[:values] << enum_value
|
|
33
|
+
end
|
|
34
|
+
schemas
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DynamicMigrations
|
|
4
|
+
module Postgres
|
|
5
|
+
class Server
|
|
6
|
+
class Database
|
|
7
|
+
module ExtensionsLoader
|
|
8
|
+
# return an array of the extensions active in this database
|
|
9
|
+
def fetch_extensions
|
|
10
|
+
rows = connection.exec(<<~SQL)
|
|
11
|
+
SELECT
|
|
12
|
+
extname AS name
|
|
13
|
+
FROM pg_extension;
|
|
14
|
+
SQL
|
|
15
|
+
|
|
16
|
+
extensions = []
|
|
17
|
+
rows.each do |row|
|
|
18
|
+
extensions << row["name"].to_sym
|
|
19
|
+
end
|
|
20
|
+
extensions
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DynamicMigrations
|
|
4
|
+
module Postgres
|
|
5
|
+
class Server
|
|
6
|
+
class Database
|
|
7
|
+
module LoadedExtensions
|
|
8
|
+
class LoadedExtensionAlreadyExistsError < StandardError
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# adds a new loaded extension for this database
|
|
12
|
+
def add_loaded_extension extension_name
|
|
13
|
+
raise ExpectedSymbolError, extension_name unless extension_name.is_a? Symbol
|
|
14
|
+
if has_loaded_extension? extension_name
|
|
15
|
+
raise(LoadedExtensionAlreadyExistsError, "Loaded extension #{extension_name} already exists")
|
|
16
|
+
end
|
|
17
|
+
# sort the hash so that the extensions are in alphabetical order by name
|
|
18
|
+
@loaded_extensions[extension_name] = true
|
|
19
|
+
sorted_extensions = {}
|
|
20
|
+
@loaded_extensions.keys.sort.each do |extension_name|
|
|
21
|
+
sorted_extensions[extension_name] = true
|
|
22
|
+
end
|
|
23
|
+
@loaded_extensions = sorted_extensions
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# returns true if this table has a loaded extension with the provided name, otherwise false
|
|
27
|
+
def has_loaded_extension? extension_name
|
|
28
|
+
raise ExpectedSymbolError, extension_name unless extension_name.is_a? Symbol
|
|
29
|
+
@loaded_extensions.key? extension_name
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# returns an array of this tables loaded extensions
|
|
33
|
+
def loaded_extensions
|
|
34
|
+
@loaded_extensions.keys
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -13,7 +13,7 @@ module DynamicMigrations
|
|
|
13
13
|
|
|
14
14
|
# recursively process the database and build all the schemas,
|
|
15
15
|
# tables and columns
|
|
16
|
-
def
|
|
16
|
+
def recursively_load_database_structure
|
|
17
17
|
validations = fetch_validations
|
|
18
18
|
fetch_structure.each do |schema_name, schema_definition|
|
|
19
19
|
schema = add_loaded_schema schema_name
|
|
@@ -39,6 +39,18 @@ module DynamicMigrations
|
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
# add any active extensions to the database
|
|
43
|
+
fetch_extensions.each do |extension_name|
|
|
44
|
+
add_loaded_extension extension_name
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# add any enums
|
|
48
|
+
fetch_enums.each do |schema_name, schema_definition|
|
|
49
|
+
schema_definition.each do |enum_name, enum_definition|
|
|
50
|
+
loaded_schema(schema_name).add_enum enum_name, enum_definition[:values], description: enum_definition[:description]
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
42
54
|
# now that the structure has been loaded, we can add keys (foreign
|
|
43
55
|
# keys need to be added last, because they can depend on tables from
|
|
44
56
|
# different schemas)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DynamicMigrations
|
|
4
|
+
module Postgres
|
|
5
|
+
class Server
|
|
6
|
+
class Database
|
|
7
|
+
class Schema
|
|
8
|
+
# This class represents a postgres enum.
|
|
9
|
+
class Enum < Source
|
|
10
|
+
class ExpectedSchemaError < StandardError
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class ExpectedValuesError < StandardError
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
attr_reader :schema
|
|
17
|
+
attr_reader :name
|
|
18
|
+
attr_reader :values
|
|
19
|
+
attr_reader :description
|
|
20
|
+
|
|
21
|
+
# initialize a new object to represent a postgres enum
|
|
22
|
+
def initialize source, schema, name, values, description: nil
|
|
23
|
+
super source
|
|
24
|
+
|
|
25
|
+
@values = []
|
|
26
|
+
|
|
27
|
+
raise ExpectedSchemaError, schema unless schema.is_a? Schema
|
|
28
|
+
@schema = schema
|
|
29
|
+
|
|
30
|
+
raise ExpectedSymbolError, name unless name.is_a? Symbol
|
|
31
|
+
@name = name
|
|
32
|
+
|
|
33
|
+
unless values.is_a?(Array) && values.count > 0
|
|
34
|
+
raise ExpectedValuesError, "Values are required for enums"
|
|
35
|
+
end
|
|
36
|
+
@values = values
|
|
37
|
+
|
|
38
|
+
unless description.nil?
|
|
39
|
+
raise ExpectedStringError, description unless description.is_a? String
|
|
40
|
+
@description = description.strip
|
|
41
|
+
@description = nil if description == ""
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# returns true if this enum has a description, otehrwise false
|
|
46
|
+
def has_description?
|
|
47
|
+
!@description.nil?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def differences_descriptions other_enum
|
|
51
|
+
method_differences_descriptions other_enum, [
|
|
52
|
+
:values
|
|
53
|
+
]
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DynamicMigrations
|
|
4
|
+
module Postgres
|
|
5
|
+
class Server
|
|
6
|
+
class Database
|
|
7
|
+
class Schema < Source
|
|
8
|
+
module Enums
|
|
9
|
+
class EnumAlreadyExistsError < StandardError
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class EnumDoesNotExistError < StandardError
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# create and add a new enum
|
|
16
|
+
def add_enum enum_name, values, description: nil
|
|
17
|
+
raise ExpectedSymbolError, enum_name unless enum_name.is_a? Symbol
|
|
18
|
+
if has_enum? enum_name
|
|
19
|
+
raise(EnumAlreadyExistsError, "Enum #{enum_name} already exists")
|
|
20
|
+
end
|
|
21
|
+
included_target = self
|
|
22
|
+
if included_target.is_a? Schema
|
|
23
|
+
new_enum = @enums[enum_name] = Enum.new source, included_target, enum_name, values, description: description
|
|
24
|
+
else
|
|
25
|
+
raise ModuleIncludedIntoUnexpectedTargetError, included_target
|
|
26
|
+
end
|
|
27
|
+
# sort the hash so that the enums are in alphabetical order by name
|
|
28
|
+
sorted_enums = {}
|
|
29
|
+
@enums.keys.sort.each do |enum_name|
|
|
30
|
+
sorted_enums[enum_name] = @enums[enum_name]
|
|
31
|
+
end
|
|
32
|
+
@enums = sorted_enums
|
|
33
|
+
# return the new enum
|
|
34
|
+
new_enum
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# return a enum by its name, raises an error if the enum does not exist
|
|
38
|
+
def enum enum_name
|
|
39
|
+
raise ExpectedSymbolError, enum_name unless enum_name.is_a? Symbol
|
|
40
|
+
raise EnumDoesNotExistError unless has_enum? enum_name
|
|
41
|
+
@enums[enum_name]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# returns true/false representing if a enum with the provided name exists
|
|
45
|
+
def has_enum? enum_name
|
|
46
|
+
raise ExpectedSymbolError, enum_name unless enum_name.is_a? Symbol
|
|
47
|
+
@enums.key? enum_name
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# returns an array of all enums in the schema
|
|
51
|
+
def enums
|
|
52
|
+
@enums.values
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def enums_hash
|
|
56
|
+
@enums
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -13,6 +13,7 @@ module DynamicMigrations
|
|
|
13
13
|
|
|
14
14
|
include Tables
|
|
15
15
|
include Functions
|
|
16
|
+
include Enums
|
|
16
17
|
|
|
17
18
|
attr_reader :database
|
|
18
19
|
attr_reader :name
|
|
@@ -26,6 +27,7 @@ module DynamicMigrations
|
|
|
26
27
|
@name = name
|
|
27
28
|
@tables = {}
|
|
28
29
|
@functions = {}
|
|
30
|
+
@enums = {}
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
end
|
|
@@ -104,7 +104,7 @@ module DynamicMigrations
|
|
|
104
104
|
|
|
105
105
|
# recursively process the database and build all the schemas,
|
|
106
106
|
# tables and columns
|
|
107
|
-
def
|
|
107
|
+
def recursively_load_database_structure
|
|
108
108
|
fetch_structure.each do |schema_name, schema_definition|
|
|
109
109
|
schema = add_loaded_schema schema_name
|
|
110
110
|
|
|
@@ -17,6 +17,10 @@ module DynamicMigrations
|
|
|
17
17
|
include LoadedSchemas
|
|
18
18
|
include ConfiguredSchemas
|
|
19
19
|
include LoadedSchemasBuilder
|
|
20
|
+
include ConfiguredExtensions
|
|
21
|
+
include LoadedExtensions
|
|
22
|
+
include EnumsLoader
|
|
23
|
+
include ExtensionsLoader
|
|
20
24
|
|
|
21
25
|
attr_reader :server
|
|
22
26
|
attr_reader :name
|
|
@@ -29,6 +33,8 @@ module DynamicMigrations
|
|
|
29
33
|
@name = name
|
|
30
34
|
@configured_schemas = {}
|
|
31
35
|
@loaded_schemas = {}
|
|
36
|
+
@configured_extensions = {}
|
|
37
|
+
@loaded_extensions = {}
|
|
32
38
|
end
|
|
33
39
|
|
|
34
40
|
# if `source` is :configuration then returns the configured schema with
|
data/lib/dynamic_migrations.rb
CHANGED
|
@@ -15,11 +15,16 @@ require "dynamic_migrations/postgres/server/database/structure_loader"
|
|
|
15
15
|
require "dynamic_migrations/postgres/server/database/validations_loader"
|
|
16
16
|
require "dynamic_migrations/postgres/server/database/keys_and_unique_constraints_loader"
|
|
17
17
|
require "dynamic_migrations/postgres/server/database/triggers_and_functions_loader"
|
|
18
|
+
require "dynamic_migrations/postgres/server/database/extensions_loader"
|
|
19
|
+
require "dynamic_migrations/postgres/server/database/enums_loader"
|
|
18
20
|
require "dynamic_migrations/postgres/server/database/loaded_schemas_builder"
|
|
19
21
|
require "dynamic_migrations/postgres/server/database/loaded_schemas"
|
|
20
22
|
require "dynamic_migrations/postgres/server/database/configured_schemas"
|
|
23
|
+
require "dynamic_migrations/postgres/server/database/loaded_extensions"
|
|
24
|
+
require "dynamic_migrations/postgres/server/database/configured_extensions"
|
|
21
25
|
|
|
22
26
|
require "dynamic_migrations/postgres/server/database/differences"
|
|
27
|
+
require "dynamic_migrations/postgres/server/database/differences/to_migrations/extensions"
|
|
23
28
|
require "dynamic_migrations/postgres/server/database/differences/to_migrations/schemas"
|
|
24
29
|
require "dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables"
|
|
25
30
|
require "dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/columns"
|
|
@@ -30,6 +35,7 @@ require "dynamic_migrations/postgres/server/database/differences/to_migrations/s
|
|
|
30
35
|
require "dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/unique_constraints"
|
|
31
36
|
require "dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/validations"
|
|
32
37
|
require "dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/functions"
|
|
38
|
+
require "dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/enums"
|
|
33
39
|
require "dynamic_migrations/postgres/server/database/differences/to_migrations"
|
|
34
40
|
|
|
35
41
|
require "dynamic_migrations/postgres/server/database"
|
|
@@ -37,8 +43,10 @@ require "dynamic_migrations/postgres/server/database/source"
|
|
|
37
43
|
|
|
38
44
|
require "dynamic_migrations/postgres/server/database/schema/tables"
|
|
39
45
|
require "dynamic_migrations/postgres/server/database/schema/functions"
|
|
46
|
+
require "dynamic_migrations/postgres/server/database/schema/enums"
|
|
40
47
|
require "dynamic_migrations/postgres/server/database/schema"
|
|
41
48
|
require "dynamic_migrations/postgres/server/database/schema/function"
|
|
49
|
+
require "dynamic_migrations/postgres/server/database/schema/enum"
|
|
42
50
|
require "dynamic_migrations/postgres/server/database/schema/table/validations"
|
|
43
51
|
require "dynamic_migrations/postgres/server/database/schema/table/indexes"
|
|
44
52
|
require "dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraints"
|
|
@@ -58,8 +66,10 @@ require "dynamic_migrations/postgres/server"
|
|
|
58
66
|
require "dynamic_migrations/postgres/connections"
|
|
59
67
|
|
|
60
68
|
require "dynamic_migrations/postgres/generator/schema"
|
|
69
|
+
require "dynamic_migrations/postgres/generator/extension"
|
|
61
70
|
require "dynamic_migrations/postgres/generator/table"
|
|
62
71
|
require "dynamic_migrations/postgres/generator/column"
|
|
72
|
+
require "dynamic_migrations/postgres/generator/enum"
|
|
63
73
|
require "dynamic_migrations/postgres/generator/foreign_key_constraint"
|
|
64
74
|
require "dynamic_migrations/postgres/generator/function"
|
|
65
75
|
require "dynamic_migrations/postgres/generator/index"
|
|
@@ -70,6 +80,7 @@ require "dynamic_migrations/postgres/generator/validation"
|
|
|
70
80
|
require "dynamic_migrations/postgres/generator"
|
|
71
81
|
require "dynamic_migrations/postgres/generator/fragment"
|
|
72
82
|
require "dynamic_migrations/postgres/generator/migration"
|
|
83
|
+
require "dynamic_migrations/postgres/generator/database_migration"
|
|
73
84
|
require "dynamic_migrations/postgres/generator/schema_migration"
|
|
74
85
|
require "dynamic_migrations/postgres/generator/table_migration"
|
|
75
86
|
require "dynamic_migrations/postgres/generator/migration_dependency_sorter"
|
|
@@ -82,6 +93,7 @@ require "dynamic_migrations/active_record/migrators/function"
|
|
|
82
93
|
require "dynamic_migrations/active_record/migrators/trigger"
|
|
83
94
|
require "dynamic_migrations/active_record/migrators/table"
|
|
84
95
|
require "dynamic_migrations/active_record/migrators/index"
|
|
96
|
+
require "dynamic_migrations/active_record/migrators/enum"
|
|
85
97
|
require "dynamic_migrations/active_record/migrators/column"
|
|
86
98
|
require "dynamic_migrations/active_record/migrators"
|
|
87
99
|
|
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.4.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-08-
|
|
11
|
+
date: 2023-08-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: pg
|
|
@@ -67,6 +67,7 @@ files:
|
|
|
67
67
|
- lib/dynamic_migrations.rb
|
|
68
68
|
- lib/dynamic_migrations/active_record/migrators.rb
|
|
69
69
|
- lib/dynamic_migrations/active_record/migrators/column.rb
|
|
70
|
+
- lib/dynamic_migrations/active_record/migrators/enum.rb
|
|
70
71
|
- lib/dynamic_migrations/active_record/migrators/foreign_key_constraint.rb
|
|
71
72
|
- lib/dynamic_migrations/active_record/migrators/function.rb
|
|
72
73
|
- lib/dynamic_migrations/active_record/migrators/index.rb
|
|
@@ -86,6 +87,9 @@ files:
|
|
|
86
87
|
- lib/dynamic_migrations/postgres/connections.rb
|
|
87
88
|
- lib/dynamic_migrations/postgres/generator.rb
|
|
88
89
|
- lib/dynamic_migrations/postgres/generator/column.rb
|
|
90
|
+
- lib/dynamic_migrations/postgres/generator/database_migration.rb
|
|
91
|
+
- lib/dynamic_migrations/postgres/generator/enum.rb
|
|
92
|
+
- lib/dynamic_migrations/postgres/generator/extension.rb
|
|
89
93
|
- lib/dynamic_migrations/postgres/generator/foreign_key_constraint.rb
|
|
90
94
|
- lib/dynamic_migrations/postgres/generator/fragment.rb
|
|
91
95
|
- lib/dynamic_migrations/postgres/generator/function.rb
|
|
@@ -102,11 +106,14 @@ files:
|
|
|
102
106
|
- lib/dynamic_migrations/postgres/generator/validation.rb
|
|
103
107
|
- lib/dynamic_migrations/postgres/server.rb
|
|
104
108
|
- lib/dynamic_migrations/postgres/server/database.rb
|
|
109
|
+
- lib/dynamic_migrations/postgres/server/database/configured_extensions.rb
|
|
105
110
|
- lib/dynamic_migrations/postgres/server/database/configured_schemas.rb
|
|
106
111
|
- lib/dynamic_migrations/postgres/server/database/connection.rb
|
|
107
112
|
- lib/dynamic_migrations/postgres/server/database/differences.rb
|
|
108
113
|
- lib/dynamic_migrations/postgres/server/database/differences/to_migrations.rb
|
|
114
|
+
- lib/dynamic_migrations/postgres/server/database/differences/to_migrations/extensions.rb
|
|
109
115
|
- lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas.rb
|
|
116
|
+
- lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/enums.rb
|
|
110
117
|
- lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/functions.rb
|
|
111
118
|
- lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables.rb
|
|
112
119
|
- lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/columns.rb
|
|
@@ -116,10 +123,15 @@ files:
|
|
|
116
123
|
- lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/triggers.rb
|
|
117
124
|
- lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/unique_constraints.rb
|
|
118
125
|
- lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/validations.rb
|
|
126
|
+
- lib/dynamic_migrations/postgres/server/database/enums_loader.rb
|
|
127
|
+
- lib/dynamic_migrations/postgres/server/database/extensions_loader.rb
|
|
119
128
|
- lib/dynamic_migrations/postgres/server/database/keys_and_unique_constraints_loader.rb
|
|
129
|
+
- lib/dynamic_migrations/postgres/server/database/loaded_extensions.rb
|
|
120
130
|
- lib/dynamic_migrations/postgres/server/database/loaded_schemas.rb
|
|
121
131
|
- lib/dynamic_migrations/postgres/server/database/loaded_schemas_builder.rb
|
|
122
132
|
- lib/dynamic_migrations/postgres/server/database/schema.rb
|
|
133
|
+
- lib/dynamic_migrations/postgres/server/database/schema/enum.rb
|
|
134
|
+
- lib/dynamic_migrations/postgres/server/database/schema/enums.rb
|
|
123
135
|
- lib/dynamic_migrations/postgres/server/database/schema/function.rb
|
|
124
136
|
- lib/dynamic_migrations/postgres/server/database/schema/functions.rb
|
|
125
137
|
- lib/dynamic_migrations/postgres/server/database/schema/table.rb
|