dynamic_migrations 3.7.0 → 3.8.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/server/database/differences/to_migrations/extensions.rb +3 -1
- data/lib/dynamic_migrations/postgres/server/database/keys_and_unique_constraints_loader.rb +6 -6
- data/lib/dynamic_migrations/postgres/server/database/loaded_schemas_builder.rb +3 -1
- data/lib/dynamic_migrations/postgres/server/database/schema/enums.rb +3 -1
- data/lib/dynamic_migrations/postgres/server/database/structure_loader.rb +35 -12
- data/lib/dynamic_migrations/postgres/server/database/validations_loader.rb +6 -6
- data/lib/dynamic_migrations/postgres.rb +27 -2
- data/lib/dynamic_migrations/version.rb +1 -1
- data/lib/dynamic_migrations.rb +2 -0
- data/sig/dynamic_migrations/postgres.rbs +8 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 437a84189a939e185f89db2de8395bc1fb8dc9f159b3948a97dcc5b04c4fedb7
|
4
|
+
data.tar.gz: 6e1df320ac06c0b0ca9d6aeb3abf684e47b9daac4ee1def93180de801f73125b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2ce93a8d273abfb0c2ede80b7564216a8409bcd8a43b8fe6c85043eed83d750f8a2b2e53996afdc241e13db9f6cdf2c3f52034a5e93965663684bc121237b54
|
7
|
+
data.tar.gz: bb3378cc475e8e3c16dd2d3a9a5754484da539d3ba1feb4839d2312c1f24cb147ea11534ba3a9bfbcda827bee4bc5ae18cc2c7a2b23bdd67c84a23503fc4fcab
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [3.8.0](https://github.com/craigulliott/dynamic_migrations/compare/v3.7.0...v3.8.0) (2023-10-04)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* configuration option to skip removing unused extensions ([5d27e36](https://github.com/craigulliott/dynamic_migrations/commit/5d27e36363dcec552ed015a196fbcf660e6b038c))
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* adding a setting to allow customizing where the schema where materialized view structure caches are created ([f3a81f8](https://github.com/craigulliott/dynamic_migrations/commit/f3a81f850dacc40ee434de77bb1d3f3c14ea0872))
|
14
|
+
* handling arrays of enums properly ([5d27e36](https://github.com/craigulliott/dynamic_migrations/commit/5d27e36363dcec552ed015a196fbcf660e6b038c))
|
15
|
+
* skipping views when loading database tables ([5d27e36](https://github.com/craigulliott/dynamic_migrations/commit/5d27e36363dcec552ed015a196fbcf660e6b038c))
|
16
|
+
|
3
17
|
## [3.7.0](https://github.com/craigulliott/dynamic_migrations/compare/v3.6.16...v3.7.0) (2023-09-27)
|
4
18
|
|
5
19
|
|
data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/extensions.rb
CHANGED
@@ -18,7 +18,9 @@ module DynamicMigrations
|
|
18
18
|
# then we need to delete it
|
19
19
|
elsif database_extension[:exists] == true && !configuration_extension[:exists]
|
20
20
|
# a migration to drop the extension
|
21
|
-
|
21
|
+
if Postgres.remove_unused_extensions?
|
22
|
+
@generator.disable_extension extension_name
|
23
|
+
end
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
@@ -7,7 +7,7 @@ module DynamicMigrations
|
|
7
7
|
module KeysAndUniqueConstraintsLoader
|
8
8
|
def create_database_keys_and_unique_constraints_cache
|
9
9
|
connection.exec(<<~SQL)
|
10
|
-
CREATE MATERIALIZED VIEW
|
10
|
+
CREATE MATERIALIZED VIEW #{Postgres.cache_schema_name}.dynamic_migrations_keys_and_unique_constraints_cache as
|
11
11
|
SELECT
|
12
12
|
c.conname AS constraint_name,
|
13
13
|
pg_get_constraintdef(c.oid, true) as constraint_definition,
|
@@ -92,16 +92,16 @@ module DynamicMigrations
|
|
92
92
|
ORDER BY schema_name, table_name;
|
93
93
|
SQL
|
94
94
|
connection.exec(<<~SQL)
|
95
|
-
CREATE UNIQUE INDEX dynamic_migrations_keys_and_unique_constraints_cache_index ON
|
95
|
+
CREATE UNIQUE INDEX dynamic_migrations_keys_and_unique_constraints_cache_index ON #{Postgres.cache_schema_name}.dynamic_migrations_keys_and_unique_constraints_cache (schema_name, table_name, constraint_name);
|
96
96
|
SQL
|
97
97
|
connection.exec(<<~SQL)
|
98
|
-
COMMENT ON MATERIALIZED VIEW
|
98
|
+
COMMENT ON MATERIALIZED VIEW #{Postgres.cache_schema_name}.dynamic_migrations_keys_and_unique_constraints_cache IS 'A cached representation of the database constraints. This is used by the dynamic migrations library and is created automatically and updated automatically after migrations have run.';
|
99
99
|
SQL
|
100
100
|
end
|
101
101
|
|
102
102
|
def refresh_database_keys_and_unique_constraints_cache
|
103
103
|
connection.exec(<<~SQL)
|
104
|
-
REFRESH MATERIALIZED VIEW
|
104
|
+
REFRESH MATERIALIZED VIEW #{Postgres.cache_schema_name}.dynamic_migrations_keys_and_unique_constraints_cache
|
105
105
|
SQL
|
106
106
|
rescue PG::UndefinedTable
|
107
107
|
create_database_keys_and_unique_constraints_cache
|
@@ -112,12 +112,12 @@ module DynamicMigrations
|
|
112
112
|
def fetch_keys_and_unique_constraints
|
113
113
|
begin
|
114
114
|
rows = connection.exec(<<~SQL)
|
115
|
-
SELECT * FROM
|
115
|
+
SELECT * FROM #{Postgres.cache_schema_name}.dynamic_migrations_keys_and_unique_constraints_cache
|
116
116
|
SQL
|
117
117
|
rescue PG::UndefinedTable
|
118
118
|
create_database_keys_and_unique_constraints_cache
|
119
119
|
rows = connection.exec(<<~SQL)
|
120
|
-
SELECT * FROM
|
120
|
+
SELECT * FROM #{Postgres.cache_schema_name}.dynamic_migrations_keys_and_unique_constraints_cache
|
121
121
|
SQL
|
122
122
|
end
|
123
123
|
|
@@ -42,7 +42,9 @@ module DynamicMigrations
|
|
42
42
|
# add each table column
|
43
43
|
table_definition[:columns].each do |column_name, column_definition|
|
44
44
|
if column_definition[:is_enum]
|
45
|
-
|
45
|
+
data_type = column_definition[:data_type].to_s
|
46
|
+
enum_full_name = column_definition[:is_array] ? data_type[0..-3] : data_type
|
47
|
+
enum_schema, enum_name = enum_full_name.split(".")
|
46
48
|
enum = table.schema.database.loaded_schema(enum_schema.to_sym).enum(enum_name.to_sym)
|
47
49
|
else
|
48
50
|
enum = nil
|
@@ -37,7 +37,9 @@ module DynamicMigrations
|
|
37
37
|
# return a enum by its name, raises an error if the enum does not exist
|
38
38
|
def enum enum_name
|
39
39
|
raise ExpectedSymbolError, enum_name unless enum_name.is_a? Symbol
|
40
|
-
|
40
|
+
unless has_enum? enum_name
|
41
|
+
raise EnumDoesNotExistError, "Enum `#{enum_name}` does not exist"
|
42
|
+
end
|
41
43
|
@enums[enum_name]
|
42
44
|
end
|
43
45
|
|
@@ -7,12 +7,14 @@ module DynamicMigrations
|
|
7
7
|
module StructureLoader
|
8
8
|
def create_database_structure_cache
|
9
9
|
connection.exec(<<~SQL)
|
10
|
-
CREATE MATERIALIZED VIEW
|
10
|
+
CREATE MATERIALIZED VIEW #{Postgres.cache_schema_name}.dynamic_migrations_structure_cache AS
|
11
11
|
SELECT
|
12
12
|
-- Name of the schema containing the table
|
13
13
|
schemata.schema_name,
|
14
14
|
-- Name of the table
|
15
15
|
tables.table_name,
|
16
|
+
-- is this a real table or a view
|
17
|
+
tables.table_type,
|
16
18
|
-- The comment which has been added to the table (if any)
|
17
19
|
table_description.description AS table_description,
|
18
20
|
-- Name of the column
|
@@ -24,6 +26,8 @@ module DynamicMigrations
|
|
24
26
|
-- YES if the column is possibly nullable, NO if
|
25
27
|
-- it is known not nullable
|
26
28
|
columns.is_nullable,
|
29
|
+
-- Is this column an array
|
30
|
+
columns.data_type = 'ARRAY' AS is_array,
|
27
31
|
-- The formatted data type (such as integer, char(5) or numeric(12,2)[])
|
28
32
|
CASE
|
29
33
|
WHEN tables.table_name IS NOT NULL THEN
|
@@ -34,12 +38,26 @@ module DynamicMigrations
|
|
34
38
|
)
|
35
39
|
END AS data_type,
|
36
40
|
-- is this an emum
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
41
|
+
CASE
|
42
|
+
WHEN columns.data_type = 'ARRAY' OR columns.data_type = 'USER-DEFINED' THEN
|
43
|
+
(
|
44
|
+
SELECT EXISTS (
|
45
|
+
SELECT 1
|
46
|
+
FROM pg_type
|
47
|
+
INNER JOIN pg_enum
|
48
|
+
ON pg_type.oid = pg_enum.enumtypid
|
49
|
+
INNER JOIN pg_namespace
|
50
|
+
ON pg_namespace.oid = pg_type.typnamespace
|
51
|
+
WHERE
|
52
|
+
-- when the column is an array, the udt_name is the name of the enum prefixed with an underscore
|
53
|
+
(columns.data_type = 'ARRAY' AND concat('_', pg_type.typname) = columns.udt_name AND pg_namespace.nspname = columns.udt_schema)
|
54
|
+
-- when the column is not an array, the udt_name is the same name as the enum
|
55
|
+
OR (columns.data_type = 'USER-DEFINED' AND pg_type.typname = columns.udt_name AND pg_namespace.nspname = columns.udt_schema)
|
56
|
+
)
|
57
|
+
)
|
58
|
+
ELSE FALSE
|
59
|
+
END
|
60
|
+
AS is_enum,
|
43
61
|
-- If data_type identifies an interval type, this column contains
|
44
62
|
-- the specification which fields the intervals include for this
|
45
63
|
-- column, e.g., YEAR TO MONTH, DAY TO SECOND, etc. If no field
|
@@ -55,20 +73,24 @@ module DynamicMigrations
|
|
55
73
|
LEFT JOIN pg_catalog.pg_description table_description ON table_description.objoid = pg_statio_all_tables.relid AND table_description.objsubid = 0
|
56
74
|
-- required for the column description/comment
|
57
75
|
LEFT JOIN pg_catalog.pg_description column_description ON column_description.objoid = pg_statio_all_tables.relid AND column_description.objsubid = columns.ordinal_position
|
58
|
-
WHERE
|
76
|
+
WHERE
|
77
|
+
-- skip internal postgres schemas
|
78
|
+
schemata.schema_name != 'information_schema'
|
59
79
|
AND schemata.schema_name != 'postgis'
|
60
80
|
AND left(schemata.schema_name, 3) != 'pg_'
|
81
|
+
-- only base tables (skip views), the null check is required for the left join as the schema might be empty
|
82
|
+
AND (tables IS NULL OR tables.table_type = 'BASE TABLE')
|
61
83
|
-- order by the schema and table names alphabetically, then by the column position in the table
|
62
84
|
ORDER BY schemata.schema_name, tables.table_schema, columns.ordinal_position
|
63
85
|
SQL
|
64
86
|
connection.exec(<<~SQL)
|
65
|
-
COMMENT ON MATERIALIZED VIEW
|
87
|
+
COMMENT ON MATERIALIZED VIEW #{Postgres.cache_schema_name}.dynamic_migrations_structure_cache IS 'A cached representation of the database structure. This is used by the dynamic migrations library and is created automatically and updated automatically after migrations have run.';
|
66
88
|
SQL
|
67
89
|
end
|
68
90
|
|
69
91
|
def refresh_database_structure_cache
|
70
92
|
connection.exec(<<~SQL)
|
71
|
-
REFRESH MATERIALIZED VIEW
|
93
|
+
REFRESH MATERIALIZED VIEW #{Postgres.cache_schema_name}.dynamic_migrations_structure_cache
|
72
94
|
SQL
|
73
95
|
rescue PG::UndefinedTable
|
74
96
|
create_database_structure_cache
|
@@ -79,12 +101,12 @@ module DynamicMigrations
|
|
79
101
|
def fetch_structure
|
80
102
|
begin
|
81
103
|
rows = connection.exec(<<~SQL)
|
82
|
-
SELECT * FROM
|
104
|
+
SELECT * FROM #{Postgres.cache_schema_name}.dynamic_migrations_structure_cache
|
83
105
|
SQL
|
84
106
|
rescue PG::UndefinedTable
|
85
107
|
create_database_structure_cache
|
86
108
|
rows = connection.exec(<<~SQL)
|
87
|
-
SELECT * FROM
|
109
|
+
SELECT * FROM #{Postgres.cache_schema_name}.dynamic_migrations_structure_cache
|
88
110
|
SQL
|
89
111
|
end
|
90
112
|
|
@@ -109,6 +131,7 @@ module DynamicMigrations
|
|
109
131
|
column[:data_type] = row["data_type"].to_sym
|
110
132
|
column[:null] = row["is_nullable"] == "YES"
|
111
133
|
column[:is_enum] = row["is_enum"] == "t"
|
134
|
+
column[:is_array] = row["is_array"] == "t"
|
112
135
|
column[:default] = row["column_default"]
|
113
136
|
column[:description] = row["column_description"]
|
114
137
|
column[:interval_type] = row["interval_type"].nil? ? nil : row["interval_type"].to_sym
|
@@ -7,7 +7,7 @@ module DynamicMigrations
|
|
7
7
|
module ValidationsLoader
|
8
8
|
def create_database_validations_cache
|
9
9
|
connection.exec(<<~SQL)
|
10
|
-
CREATE MATERIALIZED VIEW
|
10
|
+
CREATE MATERIALIZED VIEW #{Postgres.cache_schema_name}.dynamic_migrations_validations_cache AS
|
11
11
|
SELECT
|
12
12
|
nspname AS schema_name,
|
13
13
|
pg_constraint_class.relname AS table_name,
|
@@ -38,16 +38,16 @@ module DynamicMigrations
|
|
38
38
|
conname;
|
39
39
|
SQL
|
40
40
|
connection.exec(<<~SQL)
|
41
|
-
CREATE UNIQUE INDEX dynamic_migrations_validations_cache_index ON
|
41
|
+
CREATE UNIQUE INDEX dynamic_migrations_validations_cache_index ON #{Postgres.cache_schema_name}.dynamic_migrations_validations_cache (schema_name, table_name, validation_name);
|
42
42
|
SQL
|
43
43
|
connection.exec(<<~SQL)
|
44
|
-
COMMENT ON MATERIALIZED VIEW
|
44
|
+
COMMENT ON MATERIALIZED VIEW #{Postgres.cache_schema_name}.dynamic_migrations_validations_cache IS 'A cached representation of the database validations. This is used by the dynamic migrations library and is created automatically and updated automatically after migrations have run.';
|
45
45
|
SQL
|
46
46
|
end
|
47
47
|
|
48
48
|
def refresh_database_validations_cache
|
49
49
|
connection.exec(<<~SQL)
|
50
|
-
REFRESH MATERIALIZED VIEW
|
50
|
+
REFRESH MATERIALIZED VIEW #{Postgres.cache_schema_name}.dynamic_migrations_validations_cache
|
51
51
|
SQL
|
52
52
|
rescue PG::UndefinedTable
|
53
53
|
create_database_validations_cache
|
@@ -58,12 +58,12 @@ module DynamicMigrations
|
|
58
58
|
def fetch_validations
|
59
59
|
begin
|
60
60
|
rows = connection.exec(<<~SQL)
|
61
|
-
SELECT * FROM
|
61
|
+
SELECT * FROM #{Postgres.cache_schema_name}.dynamic_migrations_validations_cache
|
62
62
|
SQL
|
63
63
|
rescue PG::UndefinedTable
|
64
64
|
create_database_validations_cache
|
65
65
|
rows = connection.exec(<<~SQL)
|
66
|
-
SELECT * FROM
|
66
|
+
SELECT * FROM #{Postgres.cache_schema_name}.dynamic_migrations_validations_cache
|
67
67
|
SQL
|
68
68
|
end
|
69
69
|
|
@@ -1,8 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DynamicMigrations
|
4
|
-
# This module exists only to namespace Postgres functionality and
|
5
|
-
# make it possible to add other database/storage types in the future.
|
6
4
|
module Postgres
|
5
|
+
# The default behaviour of dynamic migrations is to generate migrations
|
6
|
+
# which remove any unused extensions.
|
7
|
+
# People don't always have control over which extensions are running on the
|
8
|
+
# database, so this behaviour can be disabled by setting
|
9
|
+
# `DynamicMigrations::Postgres.remove_unused_extensions = false`
|
10
|
+
def self.remove_unused_extensions= value
|
11
|
+
@remove_unused_extensions = value
|
12
|
+
end
|
13
|
+
|
14
|
+
# defaults to true, but can be set to false to disable the removal of unused
|
15
|
+
# extensions
|
16
|
+
def self.remove_unused_extensions?
|
17
|
+
(@remove_unused_extensions.nil? || @remove_unused_extensions) ? true : false
|
18
|
+
end
|
19
|
+
|
20
|
+
# Dynamic Migrations creates a materialized view to store a cache representation
|
21
|
+
# of various parts of the database structure, by default this is created in the
|
22
|
+
# public schema, but this can be changed by setting the otion below.
|
23
|
+
def self.cache_schema_name= value
|
24
|
+
@cache_schema_name = value
|
25
|
+
end
|
26
|
+
|
27
|
+
# defaults to true, but can be set to false to disable the removal of unused
|
28
|
+
# extensions
|
29
|
+
def self.cache_schema_name
|
30
|
+
@cache_schema_name || :public
|
31
|
+
end
|
7
32
|
end
|
8
33
|
end
|
data/lib/dynamic_migrations.rb
CHANGED
@@ -10,6 +10,8 @@ require "dynamic_migrations/expected_integer_error"
|
|
10
10
|
require "dynamic_migrations/expected_boolean_error"
|
11
11
|
require "dynamic_migrations/module_included_into_unexpected_target_error"
|
12
12
|
|
13
|
+
require "dynamic_migrations/postgres"
|
14
|
+
|
13
15
|
require "dynamic_migrations/postgres/server/database/connection"
|
14
16
|
require "dynamic_migrations/postgres/server/database/structure_loader"
|
15
17
|
require "dynamic_migrations/postgres/server/database/validations_loader"
|
@@ -1,4 +1,12 @@
|
|
1
1
|
module DynamicMigrations
|
2
2
|
module Postgres
|
3
|
+
self.@remove_unused_extensions: bool?
|
4
|
+
self.@cache_schema_name: Symbol?
|
5
|
+
|
6
|
+
def self.remove_unused_extensions=: (bool value) -> bool
|
7
|
+
def self.remove_unused_extensions?: -> bool
|
8
|
+
|
9
|
+
def self.cache_schema_name=: (Symbol value) -> Symbol
|
10
|
+
def self.cache_schema_name: -> Symbol
|
3
11
|
end
|
4
12
|
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.
|
4
|
+
version: 3.8.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-
|
11
|
+
date: 2023-10-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|