dynamic_migrations 2.2.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/lib/dynamic_migrations/active_record/migrators/column.rb +21 -0
- data/lib/dynamic_migrations/active_record/migrators/foreign_key_constraint.rb +112 -0
- data/lib/dynamic_migrations/active_record/migrators/function.rb +108 -0
- data/lib/dynamic_migrations/active_record/migrators/index.rb +27 -0
- data/lib/dynamic_migrations/active_record/migrators/schema.rb +21 -0
- data/lib/dynamic_migrations/active_record/migrators/table.rb +21 -0
- data/lib/dynamic_migrations/active_record/migrators/trigger.rb +109 -0
- data/lib/dynamic_migrations/active_record/migrators/unique_constraint.rb +63 -0
- data/lib/dynamic_migrations/active_record/migrators/validation.rb +67 -0
- data/lib/dynamic_migrations/active_record/migrators.rb +64 -0
- data/lib/dynamic_migrations/name_helper.rb +13 -0
- data/lib/dynamic_migrations/postgres/generator/column.rb +92 -0
- data/lib/dynamic_migrations/postgres/generator/foreign_key_constraint.rb +84 -0
- data/lib/dynamic_migrations/postgres/generator/fragment.rb +30 -0
- data/lib/dynamic_migrations/postgres/generator/function.rb +77 -0
- data/lib/dynamic_migrations/postgres/generator/index.rb +101 -0
- data/lib/dynamic_migrations/postgres/generator/primary_key.rb +55 -0
- data/lib/dynamic_migrations/postgres/generator/schema.rb +19 -0
- data/lib/dynamic_migrations/postgres/generator/schema_migrations/section.rb +37 -0
- data/lib/dynamic_migrations/postgres/generator/schema_migrations.rb +92 -0
- data/lib/dynamic_migrations/postgres/generator/table.rb +122 -0
- data/lib/dynamic_migrations/postgres/generator/trigger.rb +101 -0
- data/lib/dynamic_migrations/postgres/generator/unique_constraint.rb +79 -0
- data/lib/dynamic_migrations/postgres/generator/validation.rb +87 -0
- data/lib/dynamic_migrations/postgres/generator.rb +359 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/functions.rb +68 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/columns.rb +72 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/foreign_key_constraints.rb +73 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/indexes.rb +73 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/primary_key.rb +49 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/triggers.rb +73 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/unique_constraints.rb +73 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables/validations.rb +73 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas/tables.rb +80 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations/schemas.rb +48 -0
- data/lib/dynamic_migrations/postgres/server/database/differences/to_migrations.rb +59 -0
- data/lib/dynamic_migrations/postgres/server/database/differences.rb +75 -6
- data/lib/dynamic_migrations/postgres/server/database/keys_and_unique_constraints_loader.rb +35 -9
- data/lib/dynamic_migrations/postgres/server/database/loaded_schemas_builder.rb +49 -8
- data/lib/dynamic_migrations/postgres/server/database/schema/function.rb +69 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/functions.rb +63 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/column.rb +4 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/columns.rb +1 -1
- data/lib/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraint.rb +40 -5
- data/lib/dynamic_migrations/postgres/server/database/schema/table/index.rb +23 -9
- data/lib/dynamic_migrations/postgres/server/database/schema/table/primary_key.rb +21 -6
- data/lib/dynamic_migrations/postgres/server/database/schema/table/trigger.rb +151 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/triggers.rb +66 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/unique_constraint.rb +19 -9
- data/lib/dynamic_migrations/postgres/server/database/schema/table/validation.rb +20 -1
- data/lib/dynamic_migrations/postgres/server/database/schema/table.rb +15 -5
- data/lib/dynamic_migrations/postgres/server/database/schema/tables.rb +63 -0
- data/lib/dynamic_migrations/postgres/server/database/schema.rb +3 -49
- data/lib/dynamic_migrations/postgres/server/database/source.rb +21 -0
- data/lib/dynamic_migrations/postgres/server/database/structure_loader.rb +6 -6
- data/lib/dynamic_migrations/postgres/server/database/triggers_and_functions_loader.rb +131 -0
- data/lib/dynamic_migrations/postgres/server/database/validations_loader.rb +10 -4
- data/lib/dynamic_migrations/postgres/server/database.rb +2 -1
- data/lib/dynamic_migrations/postgres/server.rb +6 -0
- data/lib/dynamic_migrations/postgres.rb +1 -1
- data/lib/dynamic_migrations/version.rb +1 -1
- data/lib/dynamic_migrations.rb +47 -3
- metadata +44 -2
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DynamicMigrations
|
4
|
+
module Postgres
|
5
|
+
class Server
|
6
|
+
class Database
|
7
|
+
class Schema
|
8
|
+
class Table
|
9
|
+
# This class represents a postgres table trigger
|
10
|
+
class Trigger < Source
|
11
|
+
class ExpectedTableError < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
class UnexpectedEventManipulationError < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
class UnexpectedActionOrderError < StandardError
|
18
|
+
end
|
19
|
+
|
20
|
+
class UnexpectedActionStatementError < StandardError
|
21
|
+
end
|
22
|
+
|
23
|
+
class UnexpectedActionOrientationError < StandardError
|
24
|
+
end
|
25
|
+
|
26
|
+
class UnexpectedActionTimingError < StandardError
|
27
|
+
end
|
28
|
+
|
29
|
+
class ExpectedOldRecordsTableError < StandardError
|
30
|
+
end
|
31
|
+
|
32
|
+
class ExpectedNewRecordsTableError < StandardError
|
33
|
+
end
|
34
|
+
|
35
|
+
class ExpectedFunctionError < StandardError
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :table
|
39
|
+
attr_reader :name
|
40
|
+
attr_reader :event_manipulation
|
41
|
+
attr_reader :action_timing
|
42
|
+
attr_reader :action_order
|
43
|
+
attr_reader :action_condition
|
44
|
+
attr_reader :action_statement
|
45
|
+
attr_reader :action_orientation
|
46
|
+
attr_reader :function
|
47
|
+
attr_reader :action_reference_old_table
|
48
|
+
attr_reader :action_reference_new_table
|
49
|
+
attr_reader :description
|
50
|
+
|
51
|
+
# initialize a new object to represent a validation in a postgres table
|
52
|
+
def initialize source, table, name, action_timing:, event_manipulation:, action_order:, action_statement:, action_orientation:, function:, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, description: nil
|
53
|
+
super source
|
54
|
+
|
55
|
+
unless table.is_a? Table
|
56
|
+
raise ExpectedTableError, table
|
57
|
+
end
|
58
|
+
@table = table
|
59
|
+
|
60
|
+
unless name.is_a? Symbol
|
61
|
+
raise ExpectedSymbolError, name
|
62
|
+
end
|
63
|
+
@name = name
|
64
|
+
|
65
|
+
unless [:before, :after].include? action_timing
|
66
|
+
raise UnexpectedActionTimingError, action_timing
|
67
|
+
end
|
68
|
+
@action_timing = action_timing
|
69
|
+
|
70
|
+
unless [:insert, :delete, :update].include? event_manipulation
|
71
|
+
raise UnexpectedEventManipulationError, event_manipulation
|
72
|
+
end
|
73
|
+
@event_manipulation = event_manipulation
|
74
|
+
|
75
|
+
unless action_order.is_a?(Integer) && action_order >= 1
|
76
|
+
raise UnexpectedActionOrderError, action_order
|
77
|
+
end
|
78
|
+
@action_order = action_order
|
79
|
+
|
80
|
+
unless action_condition.nil? || action_condition.is_a?(String)
|
81
|
+
raise ExpectedStringError, action_condition
|
82
|
+
end
|
83
|
+
@action_condition = action_condition
|
84
|
+
|
85
|
+
unless action_statement.is_a?(String) && action_statement[/\AEXECUTE FUNCTION [a-z]+(_[a-z]+)*\.[a-z]+(_[a-z]+)*\(\)\z/]
|
86
|
+
raise UnexpectedActionStatementError, "unexpected action statement `#{action_statement}`, currently only `EXECUTE FUNCTION function_name()` statements are supported"
|
87
|
+
end
|
88
|
+
@action_statement = action_statement
|
89
|
+
|
90
|
+
unless [:row, :statement].include? action_orientation
|
91
|
+
raise UnexpectedActionOrientationError, action_orientation
|
92
|
+
end
|
93
|
+
@action_orientation = action_orientation
|
94
|
+
|
95
|
+
unless function.is_a? Function
|
96
|
+
raise ExpectedFunctionError, function
|
97
|
+
end
|
98
|
+
# this should never happen, but adding it just in case
|
99
|
+
unless function.source == source
|
100
|
+
raise "Internal error - function source `#{function.source}` does not match trigger source `#{source}`"
|
101
|
+
end
|
102
|
+
@function = function
|
103
|
+
# associate this trigger with the function (so they are aware of each other)
|
104
|
+
@function.add_trigger self
|
105
|
+
|
106
|
+
unless action_reference_old_table.nil? || action_reference_old_table == :old_records
|
107
|
+
raise ExpectedOldRecordsTableError, "expected :old_records or nil, but got #{action_reference_old_table}"
|
108
|
+
end
|
109
|
+
@action_reference_old_table = action_reference_old_table
|
110
|
+
|
111
|
+
unless action_reference_new_table.nil? || action_reference_new_table == :new_records
|
112
|
+
raise ExpectedNewRecordsTableError, "expected :new_records or nil, but got #{action_reference_new_table}"
|
113
|
+
end
|
114
|
+
@action_reference_new_table = action_reference_new_table
|
115
|
+
|
116
|
+
unless description.nil?
|
117
|
+
raise ExpectedStringError, description unless description.is_a? String
|
118
|
+
@description = description
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# return true if this has a description, otherwise false
|
123
|
+
def has_description?
|
124
|
+
!@description.nil?
|
125
|
+
end
|
126
|
+
|
127
|
+
def differences_descriptions other_trigger
|
128
|
+
descriptions = method_differences_descriptions other_trigger, [
|
129
|
+
:event_manipulation,
|
130
|
+
:action_timing,
|
131
|
+
:action_order,
|
132
|
+
:action_condition,
|
133
|
+
:action_statement,
|
134
|
+
:action_orientation,
|
135
|
+
:action_reference_old_table,
|
136
|
+
:action_reference_new_table
|
137
|
+
]
|
138
|
+
# add the function differences descriptions
|
139
|
+
function.differences_descriptions(other_trigger.function).each do |description|
|
140
|
+
descriptions << "function_#{description}"
|
141
|
+
end
|
142
|
+
# return the combined differences
|
143
|
+
descriptions
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DynamicMigrations
|
4
|
+
module Postgres
|
5
|
+
class Server
|
6
|
+
class Database
|
7
|
+
class Schema
|
8
|
+
class Table < Source
|
9
|
+
# This module has all the tables methods for working with triggers
|
10
|
+
module Triggers
|
11
|
+
class TriggerDoesNotExistError < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
class TriggerAlreadyExistsError < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
# returns the trigger object for the provided trigger name, and raises an
|
18
|
+
# error if the trigger does not exist
|
19
|
+
def trigger name
|
20
|
+
raise ExpectedSymbolError, name unless name.is_a? Symbol
|
21
|
+
raise TriggerDoesNotExistError unless has_trigger? name
|
22
|
+
@triggers[name]
|
23
|
+
end
|
24
|
+
|
25
|
+
# returns true if this table has a trigger with the provided name, otherwise false
|
26
|
+
def has_trigger? name
|
27
|
+
raise ExpectedSymbolError, name unless name.is_a? Symbol
|
28
|
+
@triggers.key? name
|
29
|
+
end
|
30
|
+
|
31
|
+
# returns an array of this tables triggers
|
32
|
+
def triggers
|
33
|
+
@triggers.values
|
34
|
+
end
|
35
|
+
|
36
|
+
def triggers_hash
|
37
|
+
@triggers
|
38
|
+
end
|
39
|
+
|
40
|
+
# adds a new trigger to this table, and returns it
|
41
|
+
def add_trigger name, action_timing:, event_manipulation:, action_order:, action_statement:, action_orientation:, function:, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil, description: nil
|
42
|
+
if has_trigger? name
|
43
|
+
raise(TriggerAlreadyExistsError, "Trigger #{name} already exists")
|
44
|
+
end
|
45
|
+
included_target = self
|
46
|
+
if included_target.is_a? Table
|
47
|
+
new_trigger = @triggers[name] = Trigger.new source, included_target, name, action_timing: action_timing, event_manipulation: event_manipulation, action_order: action_order, action_statement: action_statement, action_orientation: action_orientation, function: function, action_condition: action_condition, action_reference_old_table: action_reference_old_table, action_reference_new_table: action_reference_new_table, description: description
|
48
|
+
else
|
49
|
+
raise ModuleIncludedIntoUnexpectedTargetError, included_target
|
50
|
+
end
|
51
|
+
# sort the hash so that the triggers are in alphabetical order by name
|
52
|
+
sorted_triggers = {}
|
53
|
+
@triggers.keys.sort.each do |name|
|
54
|
+
sorted_triggers[name] = @triggers[name]
|
55
|
+
end
|
56
|
+
@triggers = sorted_triggers
|
57
|
+
# return the new trigger
|
58
|
+
new_trigger
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -8,17 +8,12 @@ module DynamicMigrations
|
|
8
8
|
class Table
|
9
9
|
# This class represents a postgres table unique_constraint
|
10
10
|
class UniqueConstraint < Source
|
11
|
-
INDEX_TYPES = [:btree, :hash, :gist, :gin, :bring, :spgist]
|
12
|
-
|
13
11
|
class ExpectedTableError < StandardError
|
14
12
|
end
|
15
13
|
|
16
14
|
class ExpectedArrayOfColumnsError < StandardError
|
17
15
|
end
|
18
16
|
|
19
|
-
class UnexpectedIndexTypeError < StandardError
|
20
|
-
end
|
21
|
-
|
22
17
|
class UnexpectedOrderError < StandardError
|
23
18
|
end
|
24
19
|
|
@@ -30,12 +25,12 @@ module DynamicMigrations
|
|
30
25
|
|
31
26
|
attr_reader :table
|
32
27
|
attr_reader :name
|
33
|
-
attr_reader :index_type
|
34
28
|
attr_reader :deferrable
|
35
29
|
attr_reader :initially_deferred
|
30
|
+
attr_reader :description
|
36
31
|
|
37
32
|
# initialize a new object to represent a unique_constraint in a postgres table
|
38
|
-
def initialize source, table, columns, name,
|
33
|
+
def initialize source, table, columns, name, description: nil, deferrable: false, initially_deferred: false
|
39
34
|
super source
|
40
35
|
raise ExpectedTableError, table unless table.is_a? Table
|
41
36
|
@table = table
|
@@ -53,8 +48,10 @@ module DynamicMigrations
|
|
53
48
|
raise ExpectedSymbolError, name unless name.is_a? Symbol
|
54
49
|
@name = name
|
55
50
|
|
56
|
-
|
57
|
-
|
51
|
+
unless description.nil?
|
52
|
+
raise ExpectedStringError, description unless description.is_a? String
|
53
|
+
@description = description
|
54
|
+
end
|
58
55
|
|
59
56
|
raise ExpectedBooleanError, deferrable unless [true, false].include?(deferrable)
|
60
57
|
@deferrable = deferrable
|
@@ -63,6 +60,11 @@ module DynamicMigrations
|
|
63
60
|
@initially_deferred = initially_deferred
|
64
61
|
end
|
65
62
|
|
63
|
+
# return true if this has a description, otherwise false
|
64
|
+
def has_description?
|
65
|
+
!@description.nil?
|
66
|
+
end
|
67
|
+
|
66
68
|
# return an array of this unique_constraints columns
|
67
69
|
def columns
|
68
70
|
@columns.values
|
@@ -72,6 +74,14 @@ module DynamicMigrations
|
|
72
74
|
@columns.keys
|
73
75
|
end
|
74
76
|
|
77
|
+
def differences_descriptions other_unique_constraint
|
78
|
+
method_differences_descriptions other_unique_constraint, [
|
79
|
+
:column_names,
|
80
|
+
:deferrable,
|
81
|
+
:initially_deferred
|
82
|
+
]
|
83
|
+
end
|
84
|
+
|
75
85
|
private
|
76
86
|
|
77
87
|
# used internally to set the columns from this objects initialize method
|
@@ -22,9 +22,10 @@ module DynamicMigrations
|
|
22
22
|
attr_reader :check_clause
|
23
23
|
attr_reader :deferrable
|
24
24
|
attr_reader :initially_deferred
|
25
|
+
attr_reader :description
|
25
26
|
|
26
27
|
# initialize a new object to represent a validation in a postgres table
|
27
|
-
def initialize source, table, columns, name, check_clause, deferrable: false, initially_deferred: false
|
28
|
+
def initialize source, table, columns, name, check_clause, description: nil, deferrable: false, initially_deferred: false
|
28
29
|
super source
|
29
30
|
raise ExpectedTableError, table unless table.is_a? Table
|
30
31
|
@table = table
|
@@ -45,6 +46,11 @@ module DynamicMigrations
|
|
45
46
|
raise ExpectedStringError, check_clause unless check_clause.is_a? String
|
46
47
|
@check_clause = check_clause
|
47
48
|
|
49
|
+
unless description.nil?
|
50
|
+
raise ExpectedStringError, description unless description.is_a? String
|
51
|
+
@description = description
|
52
|
+
end
|
53
|
+
|
48
54
|
raise ExpectedBooleanError, deferrable unless [true, false].include?(deferrable)
|
49
55
|
@deferrable = deferrable
|
50
56
|
|
@@ -52,6 +58,11 @@ module DynamicMigrations
|
|
52
58
|
@initially_deferred = initially_deferred
|
53
59
|
end
|
54
60
|
|
61
|
+
# return true if this has a description, otherwise false
|
62
|
+
def has_description?
|
63
|
+
!@description.nil?
|
64
|
+
end
|
65
|
+
|
55
66
|
# return an array of this validations columns
|
56
67
|
def columns
|
57
68
|
@columns.values
|
@@ -61,6 +72,14 @@ module DynamicMigrations
|
|
61
72
|
@columns.keys
|
62
73
|
end
|
63
74
|
|
75
|
+
def differences_descriptions other_validation
|
76
|
+
method_differences_descriptions other_validation, [
|
77
|
+
:check_clause,
|
78
|
+
:deferrable,
|
79
|
+
:initially_deferred
|
80
|
+
]
|
81
|
+
end
|
82
|
+
|
64
83
|
private
|
65
84
|
|
66
85
|
# used internally to set the columns from this objects initialize method
|
@@ -13,10 +13,14 @@ module DynamicMigrations
|
|
13
13
|
class PrimaryKeyDoesNotExistError < StandardError
|
14
14
|
end
|
15
15
|
|
16
|
+
class PrimaryKeyAlreadyExistsError < StandardError
|
17
|
+
end
|
18
|
+
|
16
19
|
include Columns
|
17
20
|
include Validations
|
18
21
|
include Indexes
|
19
22
|
include ForeignKeyConstraints
|
23
|
+
include Triggers
|
20
24
|
include UniqueConstraints
|
21
25
|
|
22
26
|
attr_reader :schema
|
@@ -24,20 +28,25 @@ module DynamicMigrations
|
|
24
28
|
attr_reader :description
|
25
29
|
|
26
30
|
# initialize a new object to represent a postgres table
|
27
|
-
def initialize source, schema, name, description
|
31
|
+
def initialize source, schema, name, description: nil
|
28
32
|
super source
|
33
|
+
|
29
34
|
raise ExpectedSchemaError, schema unless schema.is_a? Schema
|
35
|
+
@schema = schema
|
36
|
+
|
30
37
|
raise ExpectedSymbolError, name unless name.is_a? Symbol
|
38
|
+
@name = name
|
39
|
+
|
31
40
|
unless description.nil?
|
32
41
|
raise ExpectedStringError, description unless description.is_a? String
|
33
42
|
@description = description
|
34
43
|
end
|
35
|
-
|
36
|
-
@name = name
|
44
|
+
|
37
45
|
@columns = {}
|
38
46
|
@validations = {}
|
39
47
|
@indexes = {}
|
40
48
|
@foreign_key_constraints = {}
|
49
|
+
@triggers = {}
|
41
50
|
@unique_constraints = {}
|
42
51
|
end
|
43
52
|
|
@@ -60,10 +69,11 @@ module DynamicMigrations
|
|
60
69
|
|
61
70
|
# returns a primary key if one exists, else raises an error
|
62
71
|
def primary_key
|
63
|
-
|
72
|
+
pk = @primary_key
|
73
|
+
unless pk
|
64
74
|
raise PrimaryKeyDoesNotExistError
|
65
75
|
end
|
66
|
-
|
76
|
+
pk
|
67
77
|
end
|
68
78
|
end
|
69
79
|
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 Tables
|
9
|
+
class TableAlreadyExistsError < StandardError
|
10
|
+
end
|
11
|
+
|
12
|
+
class TableDoesNotExistError < StandardError
|
13
|
+
end
|
14
|
+
|
15
|
+
# create and add a new table from a provided table name
|
16
|
+
def add_table table_name, description: nil
|
17
|
+
raise ExpectedSymbolError, table_name unless table_name.is_a? Symbol
|
18
|
+
if has_table? table_name
|
19
|
+
raise(TableAlreadyExistsError, "Table #{table_name} already exists")
|
20
|
+
end
|
21
|
+
included_target = self
|
22
|
+
if included_target.is_a? Schema
|
23
|
+
new_table = @tables[table_name] = Table.new source, included_target, table_name, description: description
|
24
|
+
else
|
25
|
+
raise ModuleIncludedIntoUnexpectedTargetError, included_target
|
26
|
+
end
|
27
|
+
# sort the hash so that the tables are in alphabetical order by name
|
28
|
+
sorted_tables = {}
|
29
|
+
@tables.keys.sort.each do |table_name|
|
30
|
+
sorted_tables[table_name] = @tables[table_name]
|
31
|
+
end
|
32
|
+
@tables = sorted_tables
|
33
|
+
# return the new table
|
34
|
+
new_table
|
35
|
+
end
|
36
|
+
|
37
|
+
# return a table by its name, raises an error if the table does not exist
|
38
|
+
def table table_name
|
39
|
+
raise ExpectedSymbolError, table_name unless table_name.is_a? Symbol
|
40
|
+
raise TableDoesNotExistError unless has_table? table_name
|
41
|
+
@tables[table_name]
|
42
|
+
end
|
43
|
+
|
44
|
+
# returns true/false representing if a table with the provided name exists
|
45
|
+
def has_table? table_name
|
46
|
+
raise ExpectedSymbolError, table_name unless table_name.is_a? Symbol
|
47
|
+
@tables.key? table_name
|
48
|
+
end
|
49
|
+
|
50
|
+
# returns an array of all tables in the schema
|
51
|
+
def tables
|
52
|
+
@tables.values
|
53
|
+
end
|
54
|
+
|
55
|
+
def tables_hash
|
56
|
+
@tables
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -11,11 +11,8 @@ module DynamicMigrations
|
|
11
11
|
class ExpectedDatabaseError < StandardError
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
class TableDoesNotExistError < StandardError
|
18
|
-
end
|
14
|
+
include Tables
|
15
|
+
include Functions
|
19
16
|
|
20
17
|
attr_reader :database
|
21
18
|
attr_reader :name
|
@@ -28,50 +25,7 @@ module DynamicMigrations
|
|
28
25
|
@database = database
|
29
26
|
@name = name
|
30
27
|
@tables = {}
|
31
|
-
|
32
|
-
|
33
|
-
# create and add a new table from a provided table name
|
34
|
-
def add_table table_name, description = nil
|
35
|
-
raise ExpectedSymbolError, table_name unless table_name.is_a? Symbol
|
36
|
-
if has_table? table_name
|
37
|
-
raise(TableAlreadyExistsError, "Table #{table_name} already exists")
|
38
|
-
end
|
39
|
-
included_target = self
|
40
|
-
if included_target.is_a? Schema
|
41
|
-
new_table = @tables[table_name] = Table.new source, included_target, table_name, description
|
42
|
-
else
|
43
|
-
raise ModuleIncludedIntoUnexpectedTargetError, included_target
|
44
|
-
end
|
45
|
-
# sort the hash so that the tables are in alphabetical order by name
|
46
|
-
sorted_tables = {}
|
47
|
-
@tables.keys.sort.each do |table_name|
|
48
|
-
sorted_tables[table_name] = @tables[table_name]
|
49
|
-
end
|
50
|
-
@tables = sorted_tables
|
51
|
-
# return the new table
|
52
|
-
new_table
|
53
|
-
end
|
54
|
-
|
55
|
-
# return a table by its name, raises an error if the table does not exist
|
56
|
-
def table table_name
|
57
|
-
raise ExpectedSymbolError, table_name unless table_name.is_a? Symbol
|
58
|
-
raise TableDoesNotExistError unless has_table? table_name
|
59
|
-
@tables[table_name]
|
60
|
-
end
|
61
|
-
|
62
|
-
# returns true/false representing if a table with the provided name exists
|
63
|
-
def has_table? table_name
|
64
|
-
raise ExpectedSymbolError, table_name unless table_name.is_a? Symbol
|
65
|
-
@tables.key? table_name
|
66
|
-
end
|
67
|
-
|
68
|
-
# returns an array of all tables in the schema
|
69
|
-
def tables
|
70
|
-
@tables.values
|
71
|
-
end
|
72
|
-
|
73
|
-
def tables_hash
|
74
|
-
@tables
|
28
|
+
@functions = {}
|
75
29
|
end
|
76
30
|
end
|
77
31
|
end
|
@@ -30,6 +30,27 @@ module DynamicMigrations
|
|
30
30
|
raise ExpectedSymbolError, "expected Symbol but got #{value}"
|
31
31
|
end
|
32
32
|
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# used to compare two objects and return a description of the differences
|
37
|
+
# it calls the method names provided on each object and compares the results
|
38
|
+
# and returns a human readable description of the differences
|
39
|
+
def method_differences_descriptions other_object, method_names
|
40
|
+
lines = []
|
41
|
+
([:name] + method_names + [:description]).each do |method_name|
|
42
|
+
original_value = send method_name
|
43
|
+
updated_value = other_object.send method_name
|
44
|
+
if original_value != updated_value
|
45
|
+
lines << "#{method_name} changed from `#{original_value}` to `#{updated_value}`"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# return an array of lines, not a finalized string, this is because this
|
50
|
+
# method is typically called as part of a larger procedure that will compare
|
51
|
+
# other aspects of the object too
|
52
|
+
lines
|
53
|
+
end
|
33
54
|
end
|
34
55
|
end
|
35
56
|
end
|
@@ -63,12 +63,12 @@ module DynamicMigrations
|
|
63
63
|
# useful hash representing the structure of your database
|
64
64
|
def fetch_structure
|
65
65
|
begin
|
66
|
-
rows = connection.
|
66
|
+
rows = connection.exec(<<~SQL)
|
67
67
|
SELECT * FROM public.dynamic_migrations_structure_cache
|
68
68
|
SQL
|
69
69
|
rescue PG::UndefinedTable
|
70
70
|
create_database_structure_cache
|
71
|
-
rows = connection.
|
71
|
+
rows = connection.exec(<<~SQL)
|
72
72
|
SELECT * FROM public.dynamic_migrations_structure_cache
|
73
73
|
SQL
|
74
74
|
end
|
@@ -124,7 +124,7 @@ module DynamicMigrations
|
|
124
124
|
|
125
125
|
# returns a list of the schema names in this database
|
126
126
|
def fetch_schema_names
|
127
|
-
rows = connection.exec(
|
127
|
+
rows = connection.exec(<<~SQL)
|
128
128
|
SELECT schema_name
|
129
129
|
FROM information_schema.schemata;
|
130
130
|
SQL
|
@@ -137,9 +137,9 @@ module DynamicMigrations
|
|
137
137
|
|
138
138
|
# returns a list of the table names in the provided schema
|
139
139
|
def fetch_table_names schema_name
|
140
|
-
rows = connection.exec_params(
|
141
|
-
|
142
|
-
|
140
|
+
rows = connection.exec_params(<<~SQL, [schema_name.to_s])
|
141
|
+
SELECT table_name FROM information_schema.tables
|
142
|
+
WHERE table_schema = $1
|
143
143
|
SQL
|
144
144
|
table_names = rows.map { |row| row["table_name"] }
|
145
145
|
table_names.reject! { |table_name| table_name.start_with? "pg_" }
|