dynamic_migrations 2.2.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -4
  3. data/lib/dynamic_migrations/active_record/migrators/column.rb +21 -0
  4. data/lib/dynamic_migrations/active_record/migrators/foreign_key_constraint.rb +112 -0
  5. data/lib/dynamic_migrations/active_record/migrators/function.rb +108 -0
  6. data/lib/dynamic_migrations/active_record/migrators/index.rb +27 -0
  7. data/lib/dynamic_migrations/active_record/migrators/schema.rb +21 -0
  8. data/lib/dynamic_migrations/active_record/migrators/table.rb +21 -0
  9. data/lib/dynamic_migrations/active_record/migrators/trigger.rb +109 -0
  10. data/lib/dynamic_migrations/active_record/migrators/unique_constraint.rb +63 -0
  11. data/lib/dynamic_migrations/active_record/migrators/validation.rb +67 -0
  12. data/lib/dynamic_migrations/active_record/migrators.rb +64 -0
  13. data/lib/dynamic_migrations/name_helper.rb +13 -0
  14. data/lib/dynamic_migrations/postgres/generator/column.rb +92 -0
  15. data/lib/dynamic_migrations/postgres/generator/foreign_key_constraint.rb +84 -0
  16. data/lib/dynamic_migrations/postgres/generator/fragment.rb +30 -0
  17. data/lib/dynamic_migrations/postgres/generator/function.rb +77 -0
  18. data/lib/dynamic_migrations/postgres/generator/index.rb +101 -0
  19. data/lib/dynamic_migrations/postgres/generator/primary_key.rb +55 -0
  20. data/lib/dynamic_migrations/postgres/generator/schema.rb +19 -0
  21. data/lib/dynamic_migrations/postgres/generator/schema_migrations/section.rb +37 -0
  22. data/lib/dynamic_migrations/postgres/generator/schema_migrations.rb +92 -0
  23. data/lib/dynamic_migrations/postgres/generator/table.rb +122 -0
  24. data/lib/dynamic_migrations/postgres/generator/trigger.rb +101 -0
  25. data/lib/dynamic_migrations/postgres/generator/unique_constraint.rb +79 -0
  26. data/lib/dynamic_migrations/postgres/generator/validation.rb +87 -0
  27. data/lib/dynamic_migrations/postgres/generator.rb +359 -0
  28. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/functions.rb +68 -0
  29. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/columns.rb +72 -0
  30. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/foreign_key_constraints.rb +73 -0
  31. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/indexes.rb +73 -0
  32. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/primary_key.rb +49 -0
  33. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/triggers.rb +73 -0
  34. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/unique_constraints.rb +73 -0
  35. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/validations.rb +73 -0
  36. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables.rb +80 -0
  37. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas.rb +48 -0
  38. data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations.rb +59 -0
  39. data/lib/dynamic_migrations/postgres/server/database/differences.rb +81 -6
  40. data/lib/dynamic_migrations/postgres/server/database/keys_and_unique_constraints_loader.rb +35 -9
  41. data/lib/dynamic_migrations/postgres/server/database/loaded_schemas_builder.rb +49 -8
  42. data/lib/dynamic_migrations/postgres/server/database/schema/function.rb +69 -0
  43. data/lib/dynamic_migrations/postgres/server/database/schema/functions.rb +63 -0
  44. data/lib/dynamic_migrations/postgres/server/database/schema/table/column.rb +4 -0
  45. data/lib/dynamic_migrations/postgres/server/database/schema/table/columns.rb +1 -1
  46. data/lib/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraint.rb +40 -5
  47. data/lib/dynamic_migrations/postgres/server/database/schema/table/index.rb +23 -9
  48. data/lib/dynamic_migrations/postgres/server/database/schema/table/primary_key.rb +21 -6
  49. data/lib/dynamic_migrations/postgres/server/database/schema/table/trigger.rb +151 -0
  50. data/lib/dynamic_migrations/postgres/server/database/schema/table/triggers.rb +66 -0
  51. data/lib/dynamic_migrations/postgres/server/database/schema/table/unique_constraint.rb +19 -9
  52. data/lib/dynamic_migrations/postgres/server/database/schema/table/validation.rb +20 -1
  53. data/lib/dynamic_migrations/postgres/server/database/schema/table.rb +15 -5
  54. data/lib/dynamic_migrations/postgres/server/database/schema/tables.rb +63 -0
  55. data/lib/dynamic_migrations/postgres/server/database/schema.rb +3 -49
  56. data/lib/dynamic_migrations/postgres/server/database/source.rb +21 -0
  57. data/lib/dynamic_migrations/postgres/server/database/structure_loader.rb +6 -6
  58. data/lib/dynamic_migrations/postgres/server/database/triggers_and_functions_loader.rb +131 -0
  59. data/lib/dynamic_migrations/postgres/server/database/validations_loader.rb +10 -4
  60. data/lib/dynamic_migrations/postgres/server/database.rb +2 -1
  61. data/lib/dynamic_migrations/postgres/server.rb +6 -0
  62. data/lib/dynamic_migrations/postgres.rb +1 -1
  63. data/lib/dynamic_migrations/version.rb +1 -1
  64. data/lib/dynamic_migrations.rb +47 -3
  65. metadata +44 -2
@@ -0,0 +1,49 @@
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 Tables
11
+ module PrimaryKey
12
+ def process_primary_key schema_name, table_name, configuration_primary_key, database_primary_key
13
+ configuration_primary_key_exists = configuration_primary_key && configuration_primary_key[:exists]
14
+ database_primary_key_exists = database_primary_key && database_primary_key[:exists]
15
+
16
+ # If the primary_key exists in the configuration but not in the database
17
+ # then we have to create it.
18
+ if configuration_primary_key_exists == true && database_primary_key_exists == false
19
+ # a migration to create the primary_key
20
+ primary_key = @database.configured_schema(schema_name).table(table_name).primary_key
21
+ @generator.add_primary_key primary_key
22
+
23
+ # If the schema exists in the database but not in the configuration
24
+ # then we need to delete it.
25
+ elsif configuration_primary_key_exists == false && database_primary_key_exists == true
26
+ # a migration to create the primary_key
27
+ primary_key = @database.loaded_schema(schema_name).table(table_name).primary_key
28
+ @generator.remove_primary_key primary_key
29
+
30
+ # If the primary_key exists in both the configuration and database representations
31
+ elsif configuration_primary_key_exists == true && database_primary_key_exists == true
32
+ # If the definition (i.e. the column names) is different then we need to update the primary key.
33
+ if configuration_primary_key.except(:exists, :description).filter { |name, attributes| attributes[:matches] == false }.any?
34
+ # recreate the primary_key
35
+ original_primary_key = @database.loaded_schema(schema_name).table(table_name).primary_key
36
+ updated_primary_key = @database.configured_schema(schema_name).table(table_name).primary_key
37
+ @generator.recreate_primary_key original_primary_key, updated_primary_key
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -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 Tables
11
+ module Triggers
12
+ def process_triggers schema_name, table_name, configuration_triggers, database_triggers
13
+ # process all the triggers
14
+ trigger_names = (configuration_triggers.keys + database_triggers.keys).uniq
15
+ trigger_names.each do |trigger_name|
16
+ process_trigger schema_name, table_name, trigger_name, configuration_triggers[trigger_name] || {}, database_triggers[trigger_name] || {}
17
+ end
18
+ end
19
+
20
+ def process_trigger schema_name, table_name, trigger_name, configuration_trigger, database_trigger
21
+ # If the trigger exists in the configuration but not in the database
22
+ # then we have to create it.
23
+ if configuration_trigger[:exists] == true && database_trigger[:exists] == false
24
+ # a migration to create the trigger
25
+ trigger = @database.configured_schema(schema_name).table(table_name).trigger(trigger_name)
26
+ @generator.add_trigger trigger
27
+
28
+ # If the schema exists in the database but not in the configuration
29
+ # then we need to delete it.
30
+ elsif configuration_trigger[:exists] == false && database_trigger[:exists] == true
31
+ # a migration to create the trigger
32
+ trigger = @database.loaded_schema(schema_name).table(table_name).trigger(trigger_name)
33
+ @generator.remove_trigger trigger
34
+
35
+ # If the trigger exists in both the configuration and database representations
36
+ # but the definition (except description, which is handled seeprately below) is different
37
+ # then we need to update the definition.
38
+ elsif configuration_trigger.except(:exists, :description).filter { |name, attributes| attributes[:matches] == false }.any?
39
+ # recreate the trigger
40
+ original_trigger = @database.loaded_schema(schema_name).table(table_name).trigger(trigger_name)
41
+ updated_trigger = @database.configured_schema(schema_name).table(table_name).trigger(trigger_name)
42
+ @generator.recreate_trigger original_trigger, updated_trigger
43
+ # does the description also need to be updated
44
+ if configuration_trigger[:description][:matches] == false
45
+ # if the description was removed
46
+ if configuration_trigger[:description].nil?
47
+ @generator.remove_trigger_comment trigger
48
+ else
49
+ @generator.set_trigger_comment trigger
50
+ end
51
+ end
52
+
53
+ # If the trigger exists in both the configuration and database representations
54
+ # but the description is different then we need to update the description.
55
+ elsif configuration_trigger[:description][:matches] == false
56
+ trigger = @database.configured_schema(schema_name).table(table_name).trigger(trigger_name)
57
+ # if the description was removed
58
+ if configuration_trigger[:description].nil?
59
+ @generator.remove_trigger_comment trigger
60
+ else
61
+ @generator.set_trigger_comment trigger
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -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 Tables
11
+ module UniqueConstraints
12
+ def process_unique_constraints schema_name, table_name, configuration_unique_constraints, database_unique_constraints
13
+ # process all the unique_constraints
14
+ unique_constraint_names = (configuration_unique_constraints.keys + database_unique_constraints.keys).uniq
15
+ unique_constraint_names.each do |unique_constraint_name|
16
+ process_unique_constraint schema_name, table_name, unique_constraint_name, configuration_unique_constraints[unique_constraint_name] || {}, database_unique_constraints[unique_constraint_name] || {}
17
+ end
18
+ end
19
+
20
+ def process_unique_constraint schema_name, table_name, unique_constraint_name, configuration_unique_constraint, database_unique_constraint
21
+ # If the unique_constraint exists in the configuration but not in the database
22
+ # then we have to create it.
23
+ if configuration_unique_constraint[:exists] == true && database_unique_constraint[:exists] == false
24
+ # a migration to create the unique_constraint
25
+ unique_constraint = @database.configured_schema(schema_name).table(table_name).unique_constraint(unique_constraint_name)
26
+ @generator.add_unique_constraint unique_constraint
27
+
28
+ # If the schema exists in the database but not in the configuration
29
+ # then we need to delete it.
30
+ elsif configuration_unique_constraint[:exists] == false && database_unique_constraint[:exists] == true
31
+ # a migration to create the unique_constraint
32
+ unique_constraint = @database.loaded_schema(schema_name).table(table_name).unique_constraint(unique_constraint_name)
33
+ @generator.remove_unique_constraint unique_constraint
34
+
35
+ # If the unique_constraint exists in both the configuration and database representations
36
+ # but the definition (except description, which is handled seeprately below) is different
37
+ # then we need to update the definition.
38
+ elsif configuration_unique_constraint.except(:exists, :description).filter { |name, attributes| attributes[:matches] == false }.any?
39
+ # recreate the unique_constraint
40
+ original_unique_constraint = @database.loaded_schema(schema_name).table(table_name).unique_constraint(unique_constraint_name)
41
+ updated_unique_constraint = @database.configured_schema(schema_name).table(table_name).unique_constraint(unique_constraint_name)
42
+ @generator.recreate_unique_constraint original_unique_constraint, updated_unique_constraint
43
+ # does the description also need to be updated
44
+ if configuration_unique_constraint[:description][:matches] == false
45
+ # if the description was removed
46
+ if configuration_unique_constraint[:description].nil?
47
+ @generator.remove_unique_constraint_comment unique_constraint
48
+ else
49
+ @generator.set_unique_constraint_comment unique_constraint
50
+ end
51
+ end
52
+
53
+ # If the unique_constraint exists in both the configuration and database representations
54
+ # but the description is different then we need to update the description.
55
+ elsif configuration_unique_constraint[:description][:matches] == false
56
+ unique_constraint = @database.configured_schema(schema_name).table(table_name).unique_constraint(unique_constraint_name)
57
+ # if the description was removed
58
+ if configuration_unique_constraint[:description].nil?
59
+ @generator.remove_unique_constraint_comment unique_constraint
60
+ else
61
+ @generator.set_unique_constraint_comment unique_constraint
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -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 Tables
11
+ module Validations
12
+ def process_validations schema_name, table_name, configuration_validations, database_validations
13
+ # process all the validations
14
+ validation_names = (configuration_validations.keys + database_validations.keys).uniq
15
+ validation_names.each do |validation_name|
16
+ process_validation schema_name, table_name, validation_name, configuration_validations[validation_name] || {}, database_validations[validation_name] || {}
17
+ end
18
+ end
19
+
20
+ def process_validation schema_name, table_name, validation_name, configuration_validation, database_validation
21
+ # If the validation exists in the configuration but not in the database
22
+ # then we have to create it.
23
+ if configuration_validation[:exists] == true && database_validation[:exists] == false
24
+ # a migration to create the validation
25
+ validation = @database.configured_schema(schema_name).table(table_name).validation(validation_name)
26
+ @generator.add_validation validation
27
+
28
+ # If the schema exists in the database but not in the configuration
29
+ # then we need to delete it.
30
+ elsif configuration_validation[:exists] == false && database_validation[:exists] == true
31
+ # a migration to create the validation
32
+ validation = @database.loaded_schema(schema_name).table(table_name).validation(validation_name)
33
+ @generator.remove_validation validation
34
+
35
+ # If the validation exists in both the configuration and database representations
36
+ # but the definition (except description, which is handled seeprately below) is different
37
+ # then we need to update the definition.
38
+ elsif configuration_validation.except(:exists, :description).filter { |name, attributes| attributes[:matches] == false }.any?
39
+ # recreate the validation
40
+ original_validation = @database.loaded_schema(schema_name).table(table_name).validation(validation_name)
41
+ updated_validation = @database.configured_schema(schema_name).table(table_name).validation(validation_name)
42
+ @generator.recreate_validation original_validation, updated_validation
43
+ # does the description also need to be updated
44
+ if configuration_validation[:description][:matches] == false
45
+ # if the description was removed
46
+ if configuration_validation[:description].nil?
47
+ @generator.remove_validation_comment validation
48
+ else
49
+ @generator.set_validation_comment validation
50
+ end
51
+ end
52
+
53
+ # If the validation exists in both the configuration and database representations
54
+ # but the description is different then we need to update the description.
55
+ elsif configuration_validation[:description][:matches] == false
56
+ validation = @database.configured_schema(schema_name).table(table_name).validation(validation_name)
57
+ # if the description was removed
58
+ if configuration_validation[:description].nil?
59
+ @generator.remove_validation_comment validation
60
+ else
61
+ @generator.set_validation_comment validation
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,80 @@
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 Tables
11
+ def process_tables schema_name, configuration_tables, database_tables
12
+ # process all the tables
13
+ table_names = (configuration_tables.keys + database_tables.keys).uniq
14
+ table_names.each do |table_name|
15
+ process_table schema_name, table_name, configuration_tables[table_name] || {}, database_tables[table_name] || {}
16
+ end
17
+ end
18
+
19
+ def process_table schema_name, table_name, configuration_table, database_table
20
+ # If the table exists in the configuration but not in the database
21
+ # then we have to create it.
22
+ if configuration_table[:exists] == true && database_table[:exists] == false
23
+ # a migration to create the table
24
+ table = @database.configured_schema(schema_name).table(table_name)
25
+ @generator.create_table table
26
+
27
+ # we process everything else after we create the table, because the other
28
+ # database objects are dependent on the table
29
+ process_dependents schema_name, table_name, configuration_table, {}
30
+
31
+ # If the schema exists in the database but not in the configuration
32
+ # then we need to delete it.
33
+ elsif configuration_table[:exists] == false && database_table[:exists] == true
34
+ # we process everything else before we drop the table, because the other
35
+ # database objects are dependent on the table
36
+ process_dependents schema_name, table_name, {}, database_table
37
+
38
+ # a migration to remove the table
39
+ table = @database.loaded_schema(schema_name).table(table_name)
40
+ @generator.drop_table table
41
+
42
+ # If the table exists in both the configuration and database representations
43
+ # but the description is different then we need to update the description.
44
+ elsif configuration_table[:description][:matches] == false
45
+ table = @database.configured_schema(schema_name).table(table_name)
46
+ # if the description was removed
47
+ if configuration_table[:description].nil?
48
+ @generator.remove_table_comment table
49
+ else
50
+ @generator.set_table_comment table
51
+ end
52
+
53
+ # process everything else
54
+ process_dependents schema_name, table_name, configuration_table, database_table
55
+
56
+ else
57
+ # process everything else
58
+ process_dependents schema_name, table_name, configuration_table, database_table
59
+
60
+ end
61
+ end
62
+
63
+ def process_dependents schema_name, table_name, configuration_table, database_table
64
+ process_columns schema_name, table_name, configuration_table[:columns] || {}, database_table[:columns] || {}
65
+ process_foreign_key_constraints schema_name, table_name, configuration_table[:foreign_key_constraints] || {}, database_table[:foreign_key_constraints] || {}
66
+ process_indexes schema_name, table_name, configuration_table[:indexes] || {}, database_table[:indexes] || {}
67
+ process_triggers schema_name, table_name, configuration_table[:triggers] || {}, database_table[:triggers] || {}
68
+ process_unique_constraints schema_name, table_name, configuration_table[:unique_constraints] || {}, database_table[:unique_constraints] || {}
69
+ process_validations schema_name, table_name, configuration_table[:validations] || {}, database_table[:validations] || {}
70
+ # Process the primary key. The primary key is singular (max of one per table)
71
+ process_primary_key schema_name, table_name, configuration_table[:primary_key], database_table[:primary_key]
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,48 @@
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
+ def process_schema schema_name, configuration_schema, database_schema
11
+ # if the schema exists in the configuration but not in the database
12
+ # then we have to create it
13
+ if configuration_schema[:exists] == true && database_schema[:exists] == false
14
+ # a migration to create the schema
15
+ schema = @database.configured_schema schema_name
16
+ @generator.create_schema schema
17
+
18
+ # we process the tables and functions after we create the schema
19
+ # otherwise the schemas objects will not be able to be created
20
+ process_functions schema_name, configuration_schema[:functions], {}
21
+ process_tables schema_name, configuration_schema[:tables], {}
22
+
23
+ # if the schema exists in the database but not in the configuration
24
+ # then we need to delete it
25
+ elsif configuration_schema[:exists] == false && database_schema[:exists] == true
26
+ # we process the tables and functions before we drop the schema
27
+ # as this will drop any dependencies on the schema
28
+ process_functions schema_name, {}, database_schema[:functions]
29
+ process_tables schema_name, {}, database_schema[:tables]
30
+
31
+ # a migration to drop the schema
32
+ schema = @database.loaded_schema schema_name
33
+ @generator.drop_schema schema
34
+
35
+ # if the schema exists in both the configuration and database representations
36
+ # then we just need to process the tables and functions
37
+ else
38
+ process_functions schema_name, configuration_schema[:functions], database_schema[:functions]
39
+ process_tables schema_name, configuration_schema[:tables], database_schema[:tables]
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,59 @@
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
+ class UnexpectedDatabaseObjectError < StandardError
10
+ end
11
+
12
+ class UnexpectedDifferencesObjectError < StandardError
13
+ end
14
+
15
+ include Schemas
16
+ include Schemas::Functions
17
+ include Schemas::Tables
18
+ include Schemas::Tables::Columns
19
+ include Schemas::Tables::ForeignKeyConstraints
20
+ include Schemas::Tables::Indexes
21
+ include Schemas::Tables::PrimaryKey
22
+ include Schemas::Tables::Triggers
23
+ include Schemas::Tables::UniqueConstraints
24
+ include Schemas::Tables::Validations
25
+
26
+ def initialize database, differences
27
+ raise UnexpectedDatabaseObjectError, database unless database.is_a? Database
28
+ @database = database
29
+
30
+ raise UnexpectedDifferencesObjectError, differences unless differences.is_a? Differences
31
+ @differences = differences
32
+
33
+ # the generator which will build the migrations
34
+ @generator = Generator.new
35
+ end
36
+
37
+ def migrations
38
+ # process all the schemas (we can fetch the schema names from either the
39
+ # configuration or the database object)
40
+ schema_names = differences[:configuration].keys
41
+ schema_names.each do |schema_name|
42
+ process_schema schema_name, differences[:configuration][schema_name], differences[:database][schema_name]
43
+ end
44
+
45
+ # return the migrations organized by schema
46
+ @generator.migrations
47
+ end
48
+
49
+ private
50
+
51
+ def differences
52
+ @differences_hash ||= @differences.to_h
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -11,6 +11,9 @@ module DynamicMigrations
11
11
  class TableRequiredError < StandardError
12
12
  end
13
13
 
14
+ class FunctionRequiredError < StandardError
15
+ end
16
+
14
17
  class SchemaRequiredError < StandardError
15
18
  end
16
19
 
@@ -19,6 +22,12 @@ module DynamicMigrations
19
22
  @database = database
20
23
  end
21
24
 
25
+ # returns a hash of migrations for each schema which will bring the configured
26
+ # loaded database structure into alignment with the configured database structure
27
+ def to_migrations
28
+ ToMigrations.new(@database, self).migrations
29
+ end
30
+
22
31
  # return a hash representing any differenced betweek the loaded and configured
23
32
  # versions of the current database
24
33
  def to_h
@@ -53,9 +62,11 @@ module DynamicMigrations
53
62
  raise SchemaRequiredError if schema.nil?
54
63
 
55
64
  comparison_tables = comparison_schema.nil? ? {} : comparison_schema.tables_hash
65
+ comparison_functions = comparison_schema.nil? ? {} : comparison_schema.functions_hash
56
66
  {
57
67
  exists: true,
58
- tables: compare_tables(schema.tables_hash, comparison_tables)
68
+ tables: compare_tables(schema.tables_hash, comparison_tables),
69
+ functions: compare_functions(schema.functions_hash, comparison_functions)
59
70
  }
60
71
  end
61
72
 
@@ -90,12 +101,16 @@ module DynamicMigrations
90
101
  if comparison_table
91
102
  comparison_primary_key = comparison_table.has_primary_key? ? comparison_table.primary_key : nil
92
103
  comparison_columns = comparison_table.columns_hash
104
+ comparison_indexes = comparison_table.indexes_hash
105
+ comparison_triggers = comparison_table.triggers_hash
93
106
  comparison_validations = comparison_table.validations_hash
94
107
  comparison_foreign_key_constraints = comparison_table.foreign_key_constraints_hash
95
108
  comparison_unique_constraints = comparison_table.unique_constraints_hash
96
109
  else
97
110
  comparison_primary_key = {}
98
111
  comparison_columns = {}
112
+ comparison_indexes = {}
113
+ comparison_triggers = {}
99
114
  comparison_validations = {}
100
115
  comparison_foreign_key_constraints = {}
101
116
  comparison_unique_constraints = {}
@@ -108,15 +123,41 @@ module DynamicMigrations
108
123
  },
109
124
  primary_key: compare_record(primary_key, comparison_primary_key, [
110
125
  :name,
111
- :index_type
126
+ :column_names,
127
+ :description
112
128
  ]),
113
129
  columns: compare_columns(table.columns_hash, comparison_columns),
130
+ indexes: compare_indexes(table.indexes_hash, comparison_indexes),
131
+ triggers: compare_triggers(table.triggers_hash, comparison_triggers),
114
132
  validations: compare_validations(table.validations_hash, comparison_validations),
115
133
  foreign_key_constraints: compare_foreign_key_constraints(table.foreign_key_constraints_hash, comparison_foreign_key_constraints),
116
134
  unique_constraints: compare_unique_constraints(table.unique_constraints_hash, comparison_unique_constraints)
117
135
  }
118
136
  end
119
137
 
138
+ # compare two hash representations of a set of functions and return
139
+ # an object which represents the provided `functions` and any differences
140
+ # between it and the `comparison_functions`
141
+ def self.compare_functions functions, comparison_functions
142
+ result = {}
143
+ # the base functions
144
+ functions.each do |function_name, function|
145
+ result[function_name] = compare_record function, comparison_functions[function_name], [
146
+ :definition,
147
+ :description
148
+ ]
149
+ end
150
+ # look for any in the comparison list which were not in the base list
151
+ comparison_functions.each do |function_name, function|
152
+ unless result.key? function_name
153
+ result[function_name] = {
154
+ exists: false
155
+ }
156
+ end
157
+ end
158
+ result
159
+ end
160
+
120
161
  # compare two hash representations of a set of columns and return
121
162
  # an object which represents the provided `columns` and any differences
122
163
  # between it and the `comparison_columns`
@@ -144,6 +185,37 @@ module DynamicMigrations
144
185
  result
145
186
  end
146
187
 
188
+ # compare two hash representations of a set of triggers and return
189
+ # an object which represents the provided `triggers` and any differences
190
+ # between it and the `comparison_triggers`
191
+ def self.compare_triggers triggers, comparison_triggers
192
+ result = {}
193
+ # the base triggers
194
+ triggers.each do |trigger_name, trigger|
195
+ # compare this trigger to the equivilent in the comparison list
196
+ result[trigger_name] = compare_record trigger, comparison_triggers[trigger_name], [
197
+ :action_timing,
198
+ :event_manipulation,
199
+ :action_order,
200
+ :action_condition,
201
+ :action_statement,
202
+ :action_orientation,
203
+ :action_reference_old_table,
204
+ :action_reference_new_table,
205
+ :description
206
+ ]
207
+ end
208
+ # look for any triggers in the comparison list which were not in the base list
209
+ comparison_triggers.each do |trigger_name, trigger|
210
+ unless result.key? trigger_name
211
+ result[trigger_name] = {
212
+ exists: false
213
+ }
214
+ end
215
+ end
216
+ result
217
+ end
218
+
147
219
  # compare two hash representations of a set of unique_constraints and return
148
220
  # an object which represents the provided `unique_constraints` and any differences
149
221
  # between it and the `comparison_unique_constraints`
@@ -154,7 +226,7 @@ module DynamicMigrations
154
226
  # compare this unique_constraint to the equivilent in the comparison list
155
227
  result[name] = compare_record unique_constraint, comparison_unique_constraints[name], [
156
228
  :column_names,
157
- :index_type,
229
+ :description,
158
230
  :deferrable,
159
231
  :initially_deferred
160
232
  ]
@@ -180,11 +252,10 @@ module DynamicMigrations
180
252
  # compare this index to the equivilent in the comparison list
181
253
  result[name] = compare_record index, comparison_indexes[name], [
182
254
  :column_names,
255
+ :description,
183
256
  :unique,
184
257
  :where,
185
258
  :type,
186
- :deferrable,
187
- :initially_deferred,
188
259
  :order,
189
260
  :nulls_position
190
261
  ]
@@ -211,6 +282,7 @@ module DynamicMigrations
211
282
  result[name] = compare_record validation, comparison_validations[name], [
212
283
  :check_clause,
213
284
  :column_names,
285
+ :description,
214
286
  :deferrable,
215
287
  :initially_deferred
216
288
  ]
@@ -239,8 +311,11 @@ module DynamicMigrations
239
311
  :foreign_schema_name,
240
312
  :foreign_table_name,
241
313
  :foreign_column_names,
314
+ :description,
242
315
  :deferrable,
243
- :initially_deferred
316
+ :initially_deferred,
317
+ :on_delete,
318
+ :on_update
244
319
  ]
245
320
  end
246
321
  # look for any foreign_key_constraints in the comparison list which were not in the base list