dynamic_migrations 1.0.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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +13 -0
  3. data/CODE_OF_CONDUCT.md +84 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +71 -0
  6. data/lib/dynamic_migrations/expected_boolean_error.rb +4 -0
  7. data/lib/dynamic_migrations/expected_integer_error.rb +4 -0
  8. data/lib/dynamic_migrations/expected_string_error.rb +4 -0
  9. data/lib/dynamic_migrations/expected_symbol_error.rb +4 -0
  10. data/lib/dynamic_migrations/invalid_source_error.rb +7 -0
  11. data/lib/dynamic_migrations/module_included_into_unexpected_target_error.rb +4 -0
  12. data/lib/dynamic_migrations/postgres/connections.rb +42 -0
  13. data/lib/dynamic_migrations/postgres/data_types.rb +273 -0
  14. data/lib/dynamic_migrations/postgres/server/database/configured_schemas.rb +55 -0
  15. data/lib/dynamic_migrations/postgres/server/database/connection.rb +39 -0
  16. data/lib/dynamic_migrations/postgres/server/database/differences.rb +292 -0
  17. data/lib/dynamic_migrations/postgres/server/database/keys_and_unique_constraints_loader.rb +149 -0
  18. data/lib/dynamic_migrations/postgres/server/database/loaded_schemas.rb +55 -0
  19. data/lib/dynamic_migrations/postgres/server/database/loaded_schemas_builder.rb +86 -0
  20. data/lib/dynamic_migrations/postgres/server/database/schema/table/column.rb +84 -0
  21. data/lib/dynamic_migrations/postgres/server/database/schema/table/columns.rb +58 -0
  22. data/lib/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraint.rb +132 -0
  23. data/lib/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraints.rb +62 -0
  24. data/lib/dynamic_migrations/postgres/server/database/schema/table/index.rb +144 -0
  25. data/lib/dynamic_migrations/postgres/server/database/schema/table/indexes.rb +63 -0
  26. data/lib/dynamic_migrations/postgres/server/database/schema/table/primary_key.rb +83 -0
  27. data/lib/dynamic_migrations/postgres/server/database/schema/table/unique_constraint.rb +101 -0
  28. data/lib/dynamic_migrations/postgres/server/database/schema/table/unique_constraints.rb +59 -0
  29. data/lib/dynamic_migrations/postgres/server/database/schema/table/validation.rb +90 -0
  30. data/lib/dynamic_migrations/postgres/server/database/schema/table/validations.rb +59 -0
  31. data/lib/dynamic_migrations/postgres/server/database/schema/table.rb +73 -0
  32. data/lib/dynamic_migrations/postgres/server/database/schema.rb +72 -0
  33. data/lib/dynamic_migrations/postgres/server/database/source.rb +37 -0
  34. data/lib/dynamic_migrations/postgres/server/database/structure_loader.rb +242 -0
  35. data/lib/dynamic_migrations/postgres/server/database/validations_loader.rb +81 -0
  36. data/lib/dynamic_migrations/postgres/server/database.rb +54 -0
  37. data/lib/dynamic_migrations/postgres/server.rb +33 -0
  38. data/lib/dynamic_migrations/postgres.rb +8 -0
  39. data/lib/dynamic_migrations/version.rb +5 -0
  40. data/lib/dynamic_migrations.rb +44 -0
  41. metadata +113 -0
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DynamicMigrations
4
+ module Postgres
5
+ class Server
6
+ class Database
7
+ module ValidationsLoader
8
+ def create_database_validations_cache
9
+ connection.exec(<<~SQL)
10
+ CREATE MATERIALIZED VIEW public.dynamic_migrations_validations_cache as
11
+ SELECT table_constraints.table_schema as schema_name,
12
+ table_constraints.table_name,
13
+ array_agg(col.column_name ORDER BY col.column_name) AS columns,
14
+ table_constraints.constraint_name as validation_name,
15
+ check_constraints.check_clause,
16
+ 1 as table_version
17
+ FROM information_schema.table_constraints
18
+ JOIN information_schema.check_constraints
19
+ ON table_constraints.constraint_schema = check_constraints.constraint_schema
20
+ AND table_constraints.constraint_name = check_constraints.constraint_name
21
+ JOIN pg_namespace nsp ON nsp.nspname = check_constraints.constraint_schema
22
+ JOIN pg_constraint pgc ON pgc.conname = check_constraints.constraint_name
23
+ AND pgc.connamespace = nsp.oid
24
+ AND pgc.contype = 'c'
25
+ JOIN information_schema.columns col
26
+ ON col.table_schema = table_constraints.table_schema
27
+ AND col.table_name = table_constraints.table_name
28
+ AND col.ordinal_position = ANY(pgc.conkey)
29
+ WHERE table_constraints.constraint_schema != 'information_schema'
30
+ AND table_constraints.constraint_schema != 'postgis'
31
+ AND left(table_constraints.constraint_schema, 3) != 'pg_'
32
+ GROUP BY
33
+ table_constraints.table_schema,
34
+ table_constraints.table_name,
35
+ table_constraints.constraint_name,
36
+ check_constraints.check_clause;
37
+ SQL
38
+ connection.exec(<<~SQL)
39
+ CREATE UNIQUE INDEX dynamic_migrations_validations_cache_index ON public.dynamic_migrations_validations_cache (schema_name, table_name, validation_name);
40
+ SQL
41
+ connection.exec(<<~SQL)
42
+ COMMENT ON MATERIALIZED VIEW public.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.';
43
+ SQL
44
+ end
45
+
46
+ # fetch all columns from the database and build and return a
47
+ # useful hash representing the validations of your database
48
+ def fetch_validations
49
+ begin
50
+ rows = connection.exec_params(<<~SQL)
51
+ SELECT * FROM public.dynamic_migrations_validations_cache
52
+ SQL
53
+ rescue PG::UndefinedTable
54
+ create_database_validations_cache
55
+ rows = connection.exec_params(<<~SQL)
56
+ SELECT * FROM public.dynamic_migrations_validations_cache
57
+ SQL
58
+ end
59
+
60
+ schemas = {}
61
+ rows.each do |row|
62
+ schema_name = row["schema_name"].to_sym
63
+ schema = schemas[schema_name] ||= {}
64
+
65
+ table_name = row["table_name"].to_sym
66
+ table = schema[table_name] ||= {}
67
+
68
+ validation_name = row["validation_name"].to_sym
69
+
70
+ table[validation_name] = {
71
+ columns: row["columns"].gsub(/\A\{/, "").gsub(/\}\Z/, "").split(",").map { |column_name| column_name.to_sym },
72
+ check_clause: row["check_clause"]
73
+ }
74
+ end
75
+ schemas
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DynamicMigrations
4
+ module Postgres
5
+ class Server
6
+ # This class represents a postgres database. A database can contain many different
7
+ # schemas.
8
+ class Database
9
+ class ExpectedServerError < StandardError
10
+ end
11
+
12
+ include Connection
13
+ include StructureLoader
14
+ include ValidationsLoader
15
+ include KeysAndUniqueConstraintsLoader
16
+ include LoadedSchemas
17
+ include ConfiguredSchemas
18
+ include LoadedSchemasBuilder
19
+
20
+ attr_reader :server
21
+ attr_reader :database_name
22
+
23
+ # initialize a new object to represent a postgres database
24
+ def initialize server, database_name
25
+ raise ExpectedServerError, server unless server.is_a? Server
26
+ raise ExpectedSymbolError, database_name unless database_name.is_a? Symbol
27
+ @server = server
28
+ @database_name = database_name
29
+ @configured_schemas = {}
30
+ @loaded_schemas = {}
31
+ end
32
+
33
+ # if `source` is :configuration then returns the configured schema with
34
+ # the provided name, if `source` is :database then returns the loaded
35
+ # schema with the provided name, errors are raised if the requested
36
+ # schema does not exist or an unexpected `source` value is provided
37
+ def schema schema_name, source
38
+ case source
39
+ when :configuration
40
+ configured_schema schema_name
41
+ when :database
42
+ loaded_schema schema_name
43
+ else
44
+ raise InvalidSourceError, source
45
+ end
46
+ end
47
+
48
+ def differences
49
+ Differences.new(self).to_h
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DynamicMigrations
4
+ module Postgres
5
+ # This class represents a postgres server. A server can contain many databases.
6
+ class Server
7
+ attr_reader :host, :port, :username, :password
8
+
9
+ # initialize a new object to represent a postgres server
10
+ def initialize host, port, username, password
11
+ @host = host
12
+ @port = port
13
+ @username = username
14
+ @password = password
15
+ @databases = {}
16
+ end
17
+
18
+ def add_database database_name
19
+ raise ExpectedSymbolError, database_name unless database_name.is_a? Symbol
20
+ @databases[database_name] = Database.new self, database_name
21
+ end
22
+
23
+ def database database_name
24
+ raise ExpectedSymbolError, database_name unless database_name.is_a? Symbol
25
+ @databases[database_name]
26
+ end
27
+
28
+ def databases
29
+ @databases.values
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
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 futur.
6
+ module Postgres
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DynamicMigrations
4
+ VERSION = "1.0.0"
5
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pg"
4
+
5
+ require "dynamic_migrations/version"
6
+ require "dynamic_migrations/invalid_source_error"
7
+ require "dynamic_migrations/expected_symbol_error"
8
+ require "dynamic_migrations/expected_string_error"
9
+ require "dynamic_migrations/expected_integer_error"
10
+ require "dynamic_migrations/expected_boolean_error"
11
+ require "dynamic_migrations/module_included_into_unexpected_target_error"
12
+
13
+ require "dynamic_migrations/postgres/server/database/connection"
14
+ require "dynamic_migrations/postgres/server/database/structure_loader"
15
+ require "dynamic_migrations/postgres/server/database/validations_loader"
16
+ require "dynamic_migrations/postgres/server/database/keys_and_unique_constraints_loader"
17
+ require "dynamic_migrations/postgres/server/database/loaded_schemas_builder"
18
+ require "dynamic_migrations/postgres/server/database/differences"
19
+ require "dynamic_migrations/postgres/server/database/loaded_schemas"
20
+ require "dynamic_migrations/postgres/server/database/configured_schemas"
21
+ require "dynamic_migrations/postgres/server/database"
22
+ require "dynamic_migrations/postgres/server/database/source"
23
+ require "dynamic_migrations/postgres/server/database/schema"
24
+ require "dynamic_migrations/postgres/server/database/schema/table/validations"
25
+ require "dynamic_migrations/postgres/server/database/schema/table/indexes"
26
+ require "dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraints"
27
+ require "dynamic_migrations/postgres/server/database/schema/table/unique_constraints"
28
+ require "dynamic_migrations/postgres/server/database/schema/table/columns"
29
+ require "dynamic_migrations/postgres/server/database/schema/table"
30
+ require "dynamic_migrations/postgres/server/database/schema/table/column"
31
+ require "dynamic_migrations/postgres/server/database/schema/table/validation"
32
+ require "dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraint"
33
+ require "dynamic_migrations/postgres/server/database/schema/table/index"
34
+ require "dynamic_migrations/postgres/server/database/schema/table/primary_key"
35
+ require "dynamic_migrations/postgres/server/database/schema/table/unique_constraint"
36
+
37
+ require "dynamic_migrations/postgres/server"
38
+ require "dynamic_migrations/postgres/connections"
39
+ require "dynamic_migrations/postgres/data_types"
40
+
41
+ module DynamicMigrations
42
+ class Error < StandardError
43
+ end
44
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dynamic_migrations
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Craig Ulliott
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-07-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pg
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: yaml
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.2'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.2'
41
+ description: Monitor and generate database migrations based on difference between
42
+ current schema and configuration
43
+ email:
44
+ - craigulliott@gmail.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - CHANGELOG.md
50
+ - CODE_OF_CONDUCT.md
51
+ - LICENSE.txt
52
+ - README.md
53
+ - lib/dynamic_migrations.rb
54
+ - lib/dynamic_migrations/expected_boolean_error.rb
55
+ - lib/dynamic_migrations/expected_integer_error.rb
56
+ - lib/dynamic_migrations/expected_string_error.rb
57
+ - lib/dynamic_migrations/expected_symbol_error.rb
58
+ - lib/dynamic_migrations/invalid_source_error.rb
59
+ - lib/dynamic_migrations/module_included_into_unexpected_target_error.rb
60
+ - lib/dynamic_migrations/postgres.rb
61
+ - lib/dynamic_migrations/postgres/connections.rb
62
+ - lib/dynamic_migrations/postgres/data_types.rb
63
+ - lib/dynamic_migrations/postgres/server.rb
64
+ - lib/dynamic_migrations/postgres/server/database.rb
65
+ - lib/dynamic_migrations/postgres/server/database/configured_schemas.rb
66
+ - lib/dynamic_migrations/postgres/server/database/connection.rb
67
+ - lib/dynamic_migrations/postgres/server/database/differences.rb
68
+ - lib/dynamic_migrations/postgres/server/database/keys_and_unique_constraints_loader.rb
69
+ - lib/dynamic_migrations/postgres/server/database/loaded_schemas.rb
70
+ - lib/dynamic_migrations/postgres/server/database/loaded_schemas_builder.rb
71
+ - lib/dynamic_migrations/postgres/server/database/schema.rb
72
+ - lib/dynamic_migrations/postgres/server/database/schema/table.rb
73
+ - lib/dynamic_migrations/postgres/server/database/schema/table/column.rb
74
+ - lib/dynamic_migrations/postgres/server/database/schema/table/columns.rb
75
+ - lib/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraint.rb
76
+ - lib/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraints.rb
77
+ - lib/dynamic_migrations/postgres/server/database/schema/table/index.rb
78
+ - lib/dynamic_migrations/postgres/server/database/schema/table/indexes.rb
79
+ - lib/dynamic_migrations/postgres/server/database/schema/table/primary_key.rb
80
+ - lib/dynamic_migrations/postgres/server/database/schema/table/unique_constraint.rb
81
+ - lib/dynamic_migrations/postgres/server/database/schema/table/unique_constraints.rb
82
+ - lib/dynamic_migrations/postgres/server/database/schema/table/validation.rb
83
+ - lib/dynamic_migrations/postgres/server/database/schema/table/validations.rb
84
+ - lib/dynamic_migrations/postgres/server/database/source.rb
85
+ - lib/dynamic_migrations/postgres/server/database/structure_loader.rb
86
+ - lib/dynamic_migrations/postgres/server/database/validations_loader.rb
87
+ - lib/dynamic_migrations/version.rb
88
+ homepage:
89
+ licenses:
90
+ - MIT
91
+ metadata:
92
+ source_code_uri: https://github.com/craigulliott/dynamic_migrations/
93
+ changelog_uri: https://github.com/craigulliott/dynamic_migrations/blob/main/CHANGELOG.md
94
+ post_install_message:
95
+ rdoc_options: []
96
+ require_paths:
97
+ - lib
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 3.0.0
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ requirements: []
109
+ rubygems_version: 3.3.26
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Manage your database schema through configuration
113
+ test_files: []