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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +13 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +71 -0
- data/lib/dynamic_migrations/expected_boolean_error.rb +4 -0
- data/lib/dynamic_migrations/expected_integer_error.rb +4 -0
- data/lib/dynamic_migrations/expected_string_error.rb +4 -0
- data/lib/dynamic_migrations/expected_symbol_error.rb +4 -0
- data/lib/dynamic_migrations/invalid_source_error.rb +7 -0
- data/lib/dynamic_migrations/module_included_into_unexpected_target_error.rb +4 -0
- data/lib/dynamic_migrations/postgres/connections.rb +42 -0
- data/lib/dynamic_migrations/postgres/data_types.rb +273 -0
- data/lib/dynamic_migrations/postgres/server/database/configured_schemas.rb +55 -0
- data/lib/dynamic_migrations/postgres/server/database/connection.rb +39 -0
- data/lib/dynamic_migrations/postgres/server/database/differences.rb +292 -0
- data/lib/dynamic_migrations/postgres/server/database/keys_and_unique_constraints_loader.rb +149 -0
- data/lib/dynamic_migrations/postgres/server/database/loaded_schemas.rb +55 -0
- data/lib/dynamic_migrations/postgres/server/database/loaded_schemas_builder.rb +86 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/column.rb +84 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/columns.rb +58 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraint.rb +132 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/foreign_key_constraints.rb +62 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/index.rb +144 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/indexes.rb +63 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/primary_key.rb +83 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/unique_constraint.rb +101 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/unique_constraints.rb +59 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/validation.rb +90 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table/validations.rb +59 -0
- data/lib/dynamic_migrations/postgres/server/database/schema/table.rb +73 -0
- data/lib/dynamic_migrations/postgres/server/database/schema.rb +72 -0
- data/lib/dynamic_migrations/postgres/server/database/source.rb +37 -0
- data/lib/dynamic_migrations/postgres/server/database/structure_loader.rb +242 -0
- data/lib/dynamic_migrations/postgres/server/database/validations_loader.rb +81 -0
- data/lib/dynamic_migrations/postgres/server/database.rb +54 -0
- data/lib/dynamic_migrations/postgres/server.rb +33 -0
- data/lib/dynamic_migrations/postgres.rb +8 -0
- data/lib/dynamic_migrations/version.rb +5 -0
- data/lib/dynamic_migrations.rb +44 -0
- metadata +113 -0
@@ -0,0 +1,58 @@
|
|
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 columns
|
10
|
+
module Columns
|
11
|
+
class ColumnDoesNotExistError < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
class DuplicateColumnError < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
# returns the column object for the provided column name, and raises an
|
18
|
+
# error if the column does not exist
|
19
|
+
def column column_name
|
20
|
+
raise ExpectedSymbolError, column_name unless column_name.is_a? Symbol
|
21
|
+
raise ColumnDoesNotExistError unless has_column? column_name
|
22
|
+
@columns[column_name]
|
23
|
+
end
|
24
|
+
|
25
|
+
# returns true if this table has a column with the provided name, otherwise false
|
26
|
+
def has_column? column_name
|
27
|
+
raise ExpectedSymbolError, column_name unless column_name.is_a? Symbol
|
28
|
+
@columns.key? column_name
|
29
|
+
end
|
30
|
+
|
31
|
+
# returns an array of this tables columns
|
32
|
+
def columns
|
33
|
+
@columns.values
|
34
|
+
end
|
35
|
+
|
36
|
+
def columns_hash
|
37
|
+
@columns
|
38
|
+
end
|
39
|
+
|
40
|
+
# adds a new column to this table, and returns it
|
41
|
+
def add_column column_name, data_type, **column_options
|
42
|
+
if has_column? column_name
|
43
|
+
raise(DuplicateColumnError, "Column #{column_name} already exists")
|
44
|
+
end
|
45
|
+
included_target = self
|
46
|
+
if included_target.is_a? Table
|
47
|
+
@columns[column_name] = Column.new source, included_target, column_name, data_type, **column_options
|
48
|
+
else
|
49
|
+
raise ModuleIncludedIntoUnexpectedTargetError, included_target
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,132 @@
|
|
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 foreign key constraint
|
10
|
+
class ForeignKeyConstraint < Source
|
11
|
+
class ExpectedTableError < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
class ExpectedArrayOfColumnsError < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
class ExpectedDifferentTablesError < StandardError
|
18
|
+
end
|
19
|
+
|
20
|
+
class DuplicateColumnError < StandardError
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :table
|
24
|
+
attr_reader :foreign_table
|
25
|
+
attr_reader :foreign_key_constraint_name
|
26
|
+
attr_reader :deferrable
|
27
|
+
attr_reader :initially_deferred
|
28
|
+
|
29
|
+
# initialize a new object to represent a foreign_key_constraint in a postgres table
|
30
|
+
def initialize source, table, columns, foreign_table, foreign_columns, foreign_key_constraint_name, deferrable: false, initially_deferred: false
|
31
|
+
super source
|
32
|
+
|
33
|
+
raise ExpectedTableError, table unless table.is_a? Table
|
34
|
+
raise ExpectedTableError, foreign_table unless foreign_table.is_a? Table
|
35
|
+
|
36
|
+
# assert that the provided columns is an array
|
37
|
+
unless columns.is_a?(Array) && columns.count > 0
|
38
|
+
raise ExpectedArrayOfColumnsError
|
39
|
+
end
|
40
|
+
|
41
|
+
# assert that the provided foreign columns is an array
|
42
|
+
unless foreign_columns.is_a?(Array) && foreign_columns.count > 0
|
43
|
+
raise ExpectedArrayOfColumnsError
|
44
|
+
end
|
45
|
+
|
46
|
+
if table.table_name == foreign_table.table_name && table.schema.schema_name == foreign_table.schema.schema_name
|
47
|
+
raise ExpectedDifferentTablesError
|
48
|
+
end
|
49
|
+
|
50
|
+
# tables must be set before the columns are added
|
51
|
+
@table = table
|
52
|
+
@foreign_table = foreign_table
|
53
|
+
|
54
|
+
@columns = {}
|
55
|
+
columns.each do |column|
|
56
|
+
add_column column
|
57
|
+
end
|
58
|
+
|
59
|
+
@foreign_columns = {}
|
60
|
+
foreign_columns.each do |column|
|
61
|
+
add_column column, true
|
62
|
+
end
|
63
|
+
|
64
|
+
raise ExpectedSymbolError, foreign_key_constraint_name unless foreign_key_constraint_name.is_a? Symbol
|
65
|
+
@foreign_key_constraint_name = foreign_key_constraint_name
|
66
|
+
|
67
|
+
raise ExpectedBooleanError, deferrable unless [true, false].include?(deferrable)
|
68
|
+
@deferrable = deferrable
|
69
|
+
|
70
|
+
raise ExpectedBooleanError, initially_deferred unless [true, false].include?(initially_deferred)
|
71
|
+
@initially_deferred = initially_deferred
|
72
|
+
end
|
73
|
+
|
74
|
+
def columns
|
75
|
+
@columns.values
|
76
|
+
end
|
77
|
+
|
78
|
+
def column_names
|
79
|
+
@columns.keys
|
80
|
+
end
|
81
|
+
|
82
|
+
def foreign_columns
|
83
|
+
@foreign_columns.values
|
84
|
+
end
|
85
|
+
|
86
|
+
def foreign_column_names
|
87
|
+
@foreign_columns.keys
|
88
|
+
end
|
89
|
+
|
90
|
+
def foreign_schema_name
|
91
|
+
@foreign_table.schema.schema_name
|
92
|
+
end
|
93
|
+
|
94
|
+
def foreign_table_name
|
95
|
+
@foreign_table.table_name
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# used internally to set the columns from this objects initialize method
|
101
|
+
def add_column column, foreign = false
|
102
|
+
if foreign
|
103
|
+
cs = @foreign_columns
|
104
|
+
t = @foreign_table
|
105
|
+
else
|
106
|
+
cs = @columns
|
107
|
+
t = @table
|
108
|
+
end
|
109
|
+
|
110
|
+
# assert that the provided dsl name is an array of Columns
|
111
|
+
unless column.is_a? Column
|
112
|
+
raise ExpectedArrayOfColumnsError
|
113
|
+
end
|
114
|
+
|
115
|
+
# assert that the provided column exists within this foreign_key_constraints table
|
116
|
+
unless t.has_column? column.column_name
|
117
|
+
raise ExpectedArrayOfColumnsError, "One or more columns do not exist in this foreign_key_constraints table"
|
118
|
+
end
|
119
|
+
|
120
|
+
if cs.key? column.column_name
|
121
|
+
raise(DuplicateColumnError, "Column #{column.column_name} already exists")
|
122
|
+
end
|
123
|
+
|
124
|
+
cs[column.column_name] = column
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,62 @@
|
|
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 foreign keys
|
10
|
+
module ForeignKeyConstraints
|
11
|
+
class ForeignKeyConstraintDoesNotExistError < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
class ForeignKeyConstraintAlreadyExistsError < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
# returns the foreign_key_constraint object for the provided foreign_key_constraint name, and raises an
|
18
|
+
# error if the foreign_key_constraint does not exist
|
19
|
+
def foreign_key_constraint foreign_key_constraint_name
|
20
|
+
raise ExpectedSymbolError, foreign_key_constraint_name unless foreign_key_constraint_name.is_a? Symbol
|
21
|
+
raise ForeignKeyConstraintDoesNotExistError unless has_foreign_key_constraint? foreign_key_constraint_name
|
22
|
+
@foreign_key_constraints[foreign_key_constraint_name]
|
23
|
+
end
|
24
|
+
|
25
|
+
# returns true if this table has a foreign_key_constraint with the provided name, otherwise false
|
26
|
+
def has_foreign_key_constraint? foreign_key_constraint_name
|
27
|
+
raise ExpectedSymbolError, foreign_key_constraint_name unless foreign_key_constraint_name.is_a? Symbol
|
28
|
+
@foreign_key_constraints.key? foreign_key_constraint_name
|
29
|
+
end
|
30
|
+
|
31
|
+
# returns an array of this tables foreign_key_constraints
|
32
|
+
def foreign_key_constraints
|
33
|
+
@foreign_key_constraints.values
|
34
|
+
end
|
35
|
+
|
36
|
+
def foreign_key_constraints_hash
|
37
|
+
@foreign_key_constraints
|
38
|
+
end
|
39
|
+
|
40
|
+
# adds a new foreign_key_constraint to this table, and returns it
|
41
|
+
def add_foreign_key_constraint foreign_key_constraint_name, column_names, foreign_schema_name, foreign_table_name, foreign_column_names, **foreign_key_constraint_options
|
42
|
+
if has_foreign_key_constraint? foreign_key_constraint_name
|
43
|
+
raise(ForeignKeyConstraintAlreadyExistsError, "foreign_key_constraint #{foreign_key_constraint_name} already exists")
|
44
|
+
end
|
45
|
+
columns = column_names.map { |column_name| column column_name }
|
46
|
+
foreign_schema = schema.database.schema foreign_schema_name, source
|
47
|
+
foreign_table = foreign_schema.table foreign_table_name
|
48
|
+
foreign_columns = foreign_column_names.map { |column_name| foreign_table.column column_name }
|
49
|
+
included_target = self
|
50
|
+
if included_target.is_a? Table
|
51
|
+
@foreign_key_constraints[foreign_key_constraint_name] = ForeignKeyConstraint.new source, included_target, columns, foreign_table, foreign_columns, foreign_key_constraint_name, **foreign_key_constraint_options
|
52
|
+
else
|
53
|
+
raise ModuleIncludedIntoUnexpectedTargetError, included_target
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,144 @@
|
|
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 index
|
10
|
+
class Index < Source
|
11
|
+
INDEX_TYPES = [:btree, :hash, :gist, :gin, :bring, :spgist]
|
12
|
+
ORDERS = [:asc, :desc]
|
13
|
+
NULL_POSITIONS = [:first, :last]
|
14
|
+
|
15
|
+
class ExpectedTableError < StandardError
|
16
|
+
end
|
17
|
+
|
18
|
+
class ExpectedArrayOfColumnsError < StandardError
|
19
|
+
end
|
20
|
+
|
21
|
+
class UnexpectedIndexTypeError < StandardError
|
22
|
+
end
|
23
|
+
|
24
|
+
class UnexpectedOrderError < StandardError
|
25
|
+
end
|
26
|
+
|
27
|
+
class UnexpectedNullsPositionError < StandardError
|
28
|
+
end
|
29
|
+
|
30
|
+
class DuplicateColumnError < StandardError
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :table
|
34
|
+
attr_reader :index_name
|
35
|
+
attr_reader :unique
|
36
|
+
attr_reader :where
|
37
|
+
attr_reader :type
|
38
|
+
attr_reader :deferrable
|
39
|
+
attr_reader :initially_deferred
|
40
|
+
attr_reader :order
|
41
|
+
attr_reader :nulls_position
|
42
|
+
|
43
|
+
# initialize a new object to represent a index in a postgres table
|
44
|
+
def initialize source, table, columns, index_name, unique: false, where: nil, type: :btree, deferrable: false, initially_deferred: false, include_columns: [], order: :asc, nulls_position: :last
|
45
|
+
super source
|
46
|
+
raise ExpectedTableError, table unless table.is_a? Table
|
47
|
+
@table = table
|
48
|
+
@columns = {}
|
49
|
+
@include_columns = {}
|
50
|
+
|
51
|
+
# assert that the provided columns is an array
|
52
|
+
unless columns.is_a?(Array) && columns.count > 0
|
53
|
+
raise ExpectedArrayOfColumnsError
|
54
|
+
end
|
55
|
+
|
56
|
+
columns.each do |column|
|
57
|
+
add_column column
|
58
|
+
end
|
59
|
+
|
60
|
+
raise ExpectedSymbolError, index_name unless index_name.is_a? Symbol
|
61
|
+
@index_name = index_name
|
62
|
+
|
63
|
+
raise ExpectedBooleanError, unique unless [true, false].include?(unique)
|
64
|
+
@unique = unique
|
65
|
+
|
66
|
+
unless where.nil?
|
67
|
+
raise ExpectedStringError, where unless where.is_a? String
|
68
|
+
@where = where
|
69
|
+
end
|
70
|
+
|
71
|
+
raise UnexpectedIndexTypeError, type unless INDEX_TYPES.include?(type)
|
72
|
+
@type = type
|
73
|
+
|
74
|
+
raise ExpectedBooleanError, deferrable unless [true, false].include?(deferrable)
|
75
|
+
@deferrable = deferrable
|
76
|
+
|
77
|
+
raise ExpectedBooleanError, initially_deferred unless [true, false].include?(initially_deferred)
|
78
|
+
@initially_deferred = initially_deferred
|
79
|
+
|
80
|
+
# assert that the include_columns is an array (it's optional, so can be an empty array)
|
81
|
+
unless include_columns.is_a?(Array)
|
82
|
+
raise ExpectedArrayOfColumnsError
|
83
|
+
end
|
84
|
+
|
85
|
+
include_columns.each do |include_column|
|
86
|
+
add_column include_column, is_include_column: true
|
87
|
+
end
|
88
|
+
|
89
|
+
raise UnexpectedOrderError, order unless ORDERS.include?(order)
|
90
|
+
@order = order
|
91
|
+
|
92
|
+
raise UnexpectedNullsPositionError, nulls_position unless NULL_POSITIONS.include?(nulls_position)
|
93
|
+
@nulls_position = nulls_position
|
94
|
+
end
|
95
|
+
|
96
|
+
# return an array of this indexes columns
|
97
|
+
def columns
|
98
|
+
@columns.values
|
99
|
+
end
|
100
|
+
|
101
|
+
def column_names
|
102
|
+
@columns.keys
|
103
|
+
end
|
104
|
+
|
105
|
+
# return an array of this indexes include_columns
|
106
|
+
def include_columns
|
107
|
+
@include_columns.values
|
108
|
+
end
|
109
|
+
|
110
|
+
def include_column_names
|
111
|
+
@include_columns.keys
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
# used internally to set the columns from this objects initialize method
|
117
|
+
def add_column column, is_include_column: false
|
118
|
+
# assert that the provided dsl name is an array of Columns
|
119
|
+
unless column.is_a? Column
|
120
|
+
raise ExpectedArrayOfColumnsError
|
121
|
+
end
|
122
|
+
|
123
|
+
# assert that the provided column exists within this indexes table
|
124
|
+
unless @table.has_column? column.column_name
|
125
|
+
raise ExpectedArrayOfColumnsError, "One or more columns do not exist in this indexes table"
|
126
|
+
end
|
127
|
+
|
128
|
+
if @columns.key?(column.column_name) || @include_columns.key?(column.column_name)
|
129
|
+
raise(DuplicateColumnError, "Column #{column.column_name} already exists in index, or is already included")
|
130
|
+
end
|
131
|
+
|
132
|
+
if is_include_column
|
133
|
+
@include_columns[column.column_name] = column
|
134
|
+
else
|
135
|
+
@columns[column.column_name] = column
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
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
|
8
|
+
class Table < Source
|
9
|
+
# This module has all the tables methods for working with indexes
|
10
|
+
module Indexes
|
11
|
+
class IndexDoesNotExistError < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
class IndexAlreadyExistsError < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
# returns the index object for the provided index name, and raises an
|
18
|
+
# error if the index does not exist
|
19
|
+
def index index_name
|
20
|
+
raise ExpectedSymbolError, index_name unless index_name.is_a? Symbol
|
21
|
+
raise IndexDoesNotExistError unless has_index? index_name
|
22
|
+
@indexes[index_name]
|
23
|
+
end
|
24
|
+
|
25
|
+
# returns true if this table has a index with the provided name, otherwise false
|
26
|
+
def has_index? index_name
|
27
|
+
raise ExpectedSymbolError, index_name unless index_name.is_a? Symbol
|
28
|
+
@indexes.key? index_name
|
29
|
+
end
|
30
|
+
|
31
|
+
# returns an array of this tables indexes
|
32
|
+
def indexes
|
33
|
+
@indexes.values
|
34
|
+
end
|
35
|
+
|
36
|
+
def indexes_hash
|
37
|
+
@indexes
|
38
|
+
end
|
39
|
+
|
40
|
+
# adds a new index to this table, and returns it
|
41
|
+
# include_column_names in broken out from index_options, because it is converted from an
|
42
|
+
# array of column names into an array of columns, and then recombined with the other
|
43
|
+
# options which are sent to the index initialize method
|
44
|
+
def add_index index_name, column_names, include_column_names: [], **index_options
|
45
|
+
if has_index? index_name
|
46
|
+
raise(IndexAlreadyExistsError, "index #{index_name} already exists")
|
47
|
+
end
|
48
|
+
columns = column_names.map { |column_name| column column_name }
|
49
|
+
include_columns = include_column_names.map { |column_name| column column_name }
|
50
|
+
included_target = self
|
51
|
+
if included_target.is_a? Table
|
52
|
+
@indexes[index_name] = Index.new source, included_target, columns, index_name, include_columns: include_columns, **index_options
|
53
|
+
else
|
54
|
+
raise ModuleIncludedIntoUnexpectedTargetError, included_target
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,83 @@
|
|
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 primary_key
|
10
|
+
class PrimaryKey < Source
|
11
|
+
INDEX_TYPES = [:btree, :gin]
|
12
|
+
|
13
|
+
class ExpectedTableError < StandardError
|
14
|
+
end
|
15
|
+
|
16
|
+
class ExpectedArrayOfColumnsError < StandardError
|
17
|
+
end
|
18
|
+
|
19
|
+
class UnexpectedIndexTypeError < StandardError
|
20
|
+
end
|
21
|
+
|
22
|
+
class DuplicateColumnError < StandardError
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :table
|
26
|
+
attr_reader :primary_key_name
|
27
|
+
attr_reader :index_type
|
28
|
+
|
29
|
+
# initialize a new object to represent a primary_key in a postgres table
|
30
|
+
def initialize source, table, columns, primary_key_name, index_type: :btree
|
31
|
+
super source
|
32
|
+
raise ExpectedTableError, table unless table.is_a? Table
|
33
|
+
@table = table
|
34
|
+
@columns = {}
|
35
|
+
|
36
|
+
# assert that the provided columns is an array
|
37
|
+
unless columns.is_a?(Array) && columns.count > 0
|
38
|
+
raise ExpectedArrayOfColumnsError
|
39
|
+
end
|
40
|
+
|
41
|
+
columns.each do |column|
|
42
|
+
add_column column
|
43
|
+
end
|
44
|
+
|
45
|
+
raise ExpectedSymbolError, primary_key_name unless primary_key_name.is_a? Symbol
|
46
|
+
@primary_key_name = primary_key_name
|
47
|
+
|
48
|
+
raise UnexpectedIndexTypeError, index_type unless INDEX_TYPES.include?(index_type)
|
49
|
+
@index_type = index_type
|
50
|
+
end
|
51
|
+
|
52
|
+
# return an array of this primary keys columns
|
53
|
+
def columns
|
54
|
+
@columns.values
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# used internally to set the columns from this objects initialize method
|
60
|
+
def add_column column
|
61
|
+
# assert that the provided dsl name is an array of Columns
|
62
|
+
unless column.is_a? Column
|
63
|
+
raise ExpectedArrayOfColumnsError
|
64
|
+
end
|
65
|
+
|
66
|
+
# assert that the provided column exists within this primary keys table
|
67
|
+
unless @table.has_column? column.column_name
|
68
|
+
raise ExpectedArrayOfColumnsError, "One or more columns do not exist in this primary keys table"
|
69
|
+
end
|
70
|
+
|
71
|
+
if @columns.key?(column.column_name)
|
72
|
+
raise(DuplicateColumnError, "Column #{column.column_name} already exists in primary_key, or is already included")
|
73
|
+
end
|
74
|
+
|
75
|
+
@columns[column.column_name] = column
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,101 @@
|
|
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 unique_constraint
|
10
|
+
class UniqueConstraint < Source
|
11
|
+
INDEX_TYPES = [:btree, :hash, :gist, :gin, :bring, :spgist]
|
12
|
+
|
13
|
+
class ExpectedTableError < StandardError
|
14
|
+
end
|
15
|
+
|
16
|
+
class ExpectedArrayOfColumnsError < StandardError
|
17
|
+
end
|
18
|
+
|
19
|
+
class UnexpectedIndexTypeError < StandardError
|
20
|
+
end
|
21
|
+
|
22
|
+
class UnexpectedOrderError < StandardError
|
23
|
+
end
|
24
|
+
|
25
|
+
class UnexpectedNullsPositionError < StandardError
|
26
|
+
end
|
27
|
+
|
28
|
+
class DuplicateColumnError < StandardError
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :table
|
32
|
+
attr_reader :unique_constraint_name
|
33
|
+
attr_reader :index_type
|
34
|
+
attr_reader :deferrable
|
35
|
+
attr_reader :initially_deferred
|
36
|
+
|
37
|
+
# initialize a new object to represent a unique_constraint in a postgres table
|
38
|
+
def initialize source, table, columns, unique_constraint_name, index_type: :btree, deferrable: false, initially_deferred: false
|
39
|
+
super source
|
40
|
+
raise ExpectedTableError, table unless table.is_a? Table
|
41
|
+
@table = table
|
42
|
+
@columns = {}
|
43
|
+
|
44
|
+
# assert that the provided columns is an array
|
45
|
+
unless columns.is_a?(Array) && columns.count > 0
|
46
|
+
raise ExpectedArrayOfColumnsError
|
47
|
+
end
|
48
|
+
|
49
|
+
columns.each do |column|
|
50
|
+
add_column column
|
51
|
+
end
|
52
|
+
|
53
|
+
raise ExpectedSymbolError, unique_constraint_name unless unique_constraint_name.is_a? Symbol
|
54
|
+
@unique_constraint_name = unique_constraint_name
|
55
|
+
|
56
|
+
raise UnexpectedIndexTypeError, index_type unless INDEX_TYPES.include?(index_type)
|
57
|
+
@index_type = index_type
|
58
|
+
|
59
|
+
raise ExpectedBooleanError, deferrable unless [true, false].include?(deferrable)
|
60
|
+
@deferrable = deferrable
|
61
|
+
|
62
|
+
raise ExpectedBooleanError, initially_deferred unless [true, false].include?(initially_deferred)
|
63
|
+
@initially_deferred = initially_deferred
|
64
|
+
end
|
65
|
+
|
66
|
+
# return an array of this unique_constraints columns
|
67
|
+
def columns
|
68
|
+
@columns.values
|
69
|
+
end
|
70
|
+
|
71
|
+
def column_names
|
72
|
+
@columns.keys
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
# used internally to set the columns from this objects initialize method
|
78
|
+
def add_column column
|
79
|
+
# assert that the provided dsl name is an array of Columns
|
80
|
+
unless column.is_a? Column
|
81
|
+
raise ExpectedArrayOfColumnsError
|
82
|
+
end
|
83
|
+
|
84
|
+
# assert that the provided column exists within this unique_constraints table
|
85
|
+
unless @table.has_column? column.column_name
|
86
|
+
raise ExpectedArrayOfColumnsError, "One or more columns do not exist in this unique_constraints table"
|
87
|
+
end
|
88
|
+
|
89
|
+
if @columns.key?(column.column_name)
|
90
|
+
raise(DuplicateColumnError, "Column #{column.column_name} already exists in unique_constraint, or is already included")
|
91
|
+
end
|
92
|
+
|
93
|
+
@columns[column.column_name] = column
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|