rom-sql 2.0.0.beta2 → 2.0.0.beta3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +66 -0
- data/lib/rom/plugins/relation/sql/postgres/explain.rb +54 -0
- data/lib/rom/sql.rb +1 -1
- data/lib/rom/sql/attribute.rb +17 -18
- data/lib/rom/sql/errors.rb +3 -0
- data/lib/rom/sql/extensions/mysql.rb +1 -1
- data/lib/rom/sql/extensions/mysql/type_builder.rb +28 -0
- data/lib/rom/sql/extensions/postgres.rb +3 -1
- data/lib/rom/sql/extensions/postgres/commands.rb +30 -13
- data/lib/rom/sql/extensions/postgres/{attributes_inferrer.rb → type_builder.rb} +24 -28
- data/lib/rom/sql/extensions/postgres/type_serializer.rb +39 -0
- data/lib/rom/sql/extensions/postgres/types.rb +24 -477
- data/lib/rom/sql/extensions/postgres/types/array.rb +163 -0
- data/lib/rom/sql/extensions/postgres/types/geometric.rb +135 -0
- data/lib/rom/sql/extensions/postgres/types/json.rb +235 -0
- data/lib/rom/sql/extensions/postgres/types/network.rb +15 -0
- data/lib/rom/sql/extensions/sqlite.rb +1 -1
- data/lib/rom/sql/extensions/sqlite/{attributes_inferrer.rb → type_builder.rb} +5 -5
- data/lib/rom/sql/extensions/sqlite/types.rb +8 -3
- data/lib/rom/sql/foreign_key.rb +17 -0
- data/lib/rom/sql/function.rb +86 -8
- data/lib/rom/sql/gateway.rb +26 -26
- data/lib/rom/sql/index.rb +4 -0
- data/lib/rom/sql/migration.rb +3 -3
- data/lib/rom/sql/migration/inline_runner.rb +9 -83
- data/lib/rom/sql/migration/migrator.rb +35 -12
- data/lib/rom/sql/migration/recorder.rb +21 -0
- data/lib/rom/sql/migration/runner.rb +115 -0
- data/lib/rom/sql/migration/schema_diff.rb +108 -53
- data/lib/rom/sql/migration/writer.rb +61 -0
- data/lib/rom/sql/relation.rb +2 -1
- data/lib/rom/sql/relation/reading.rb +63 -3
- data/lib/rom/sql/relation/writing.rb +38 -0
- data/lib/rom/sql/schema.rb +9 -3
- data/lib/rom/sql/schema/attributes_inferrer.rb +3 -119
- data/lib/rom/sql/schema/inferrer.rb +99 -18
- data/lib/rom/sql/schema/type_builder.rb +94 -0
- data/lib/rom/sql/type_dsl.rb +30 -0
- data/lib/rom/sql/type_extensions.rb +11 -6
- data/lib/rom/sql/type_serializer.rb +46 -0
- data/lib/rom/sql/types.rb +12 -0
- data/lib/rom/sql/version.rb +1 -1
- metadata +26 -244
- data/.codeclimate.yml +0 -15
- data/.gitignore +0 -17
- data/.rspec +0 -3
- data/.travis.yml +0 -39
- data/.yardopts +0 -2
- data/Gemfile +0 -33
- data/Guardfile +0 -24
- data/LICENSE.txt +0 -22
- data/Rakefile +0 -19
- data/circle.yml +0 -10
- data/lib/rom/sql/extensions/mysql/attributes_inferrer.rb +0 -10
- data/lib/rom/sql/relation/sequel_api.rb +0 -133
- data/log/.gitkeep +0 -0
- data/rom-sql.gemspec +0 -29
- data/spec/extensions/postgres/attribute_spec.rb +0 -217
- data/spec/extensions/postgres/integration_spec.rb +0 -59
- data/spec/extensions/postgres/types_spec.rb +0 -252
- data/spec/extensions/sqlite/types_spec.rb +0 -11
- data/spec/fixtures/migrations/20150403090603_create_carrots.rb +0 -8
- data/spec/integration/associations/many_to_many/custom_fks_spec.rb +0 -76
- data/spec/integration/associations/many_to_many/from_view_spec.rb +0 -88
- data/spec/integration/associations/many_to_many_spec.rb +0 -162
- data/spec/integration/associations/many_to_one/custom_fks_spec.rb +0 -64
- data/spec/integration/associations/many_to_one/from_view_spec.rb +0 -84
- data/spec/integration/associations/many_to_one/self_ref_spec.rb +0 -53
- data/spec/integration/associations/many_to_one_spec.rb +0 -117
- data/spec/integration/associations/one_to_many/custom_fks_spec.rb +0 -54
- data/spec/integration/associations/one_to_many/from_view_spec.rb +0 -57
- data/spec/integration/associations/one_to_many/self_ref_spec.rb +0 -54
- data/spec/integration/associations/one_to_many_spec.rb +0 -86
- data/spec/integration/associations/one_to_one_spec.rb +0 -69
- data/spec/integration/associations/one_to_one_through_spec.rb +0 -92
- data/spec/integration/auto_migrations/errors_spec.rb +0 -31
- data/spec/integration/auto_migrations/indexes_spec.rb +0 -253
- data/spec/integration/auto_migrations/managing_columns_spec.rb +0 -156
- data/spec/integration/auto_migrations/postgres/column_types_spec.rb +0 -63
- data/spec/integration/combine_with_spec.rb +0 -43
- data/spec/integration/commands/create_spec.rb +0 -304
- data/spec/integration/commands/delete_spec.rb +0 -84
- data/spec/integration/commands/update_spec.rb +0 -90
- data/spec/integration/commands/upsert_spec.rb +0 -83
- data/spec/integration/gateway_spec.rb +0 -107
- data/spec/integration/migration_spec.rb +0 -55
- data/spec/integration/plugins/associates/many_to_many_spec.rb +0 -69
- data/spec/integration/plugins/associates_spec.rb +0 -250
- data/spec/integration/plugins/auto_restrictions_spec.rb +0 -74
- data/spec/integration/relation_schema_spec.rb +0 -271
- data/spec/integration/schema/call_spec.rb +0 -24
- data/spec/integration/schema/inferrer/mysql_spec.rb +0 -45
- data/spec/integration/schema/inferrer/postgres_spec.rb +0 -203
- data/spec/integration/schema/inferrer/sqlite_spec.rb +0 -37
- data/spec/integration/schema/inferrer_spec.rb +0 -390
- data/spec/integration/schema/prefix_spec.rb +0 -16
- data/spec/integration/schema/qualified_spec.rb +0 -16
- data/spec/integration/schema/rename_spec.rb +0 -21
- data/spec/integration/schema/view_spec.rb +0 -29
- data/spec/integration/sequel_api_spec.rb +0 -36
- data/spec/integration/setup_spec.rb +0 -26
- data/spec/integration/support/active_support_notifications_spec.rb +0 -24
- data/spec/integration/support/rails_log_subscriber_spec.rb +0 -30
- data/spec/integration/wrap_spec.rb +0 -91
- data/spec/shared/accounts.rb +0 -48
- data/spec/shared/database_setup.rb +0 -70
- data/spec/shared/notes.rb +0 -23
- data/spec/shared/posts.rb +0 -34
- data/spec/shared/puppies.rb +0 -15
- data/spec/shared/relations.rb +0 -8
- data/spec/shared/users.rb +0 -32
- data/spec/shared/users_and_tasks.rb +0 -50
- data/spec/spec_helper.rb +0 -122
- data/spec/support/env_helper.rb +0 -25
- data/spec/support/helpers.rb +0 -24
- data/spec/support/oracle/create_users.sql +0 -7
- data/spec/support/oracle/set_sys_passwords.sql +0 -2
- data/spec/support/test_configuration.rb +0 -16
- data/spec/unit/attribute_spec.rb +0 -104
- data/spec/unit/function_spec.rb +0 -48
- data/spec/unit/gateway_spec.rb +0 -70
- data/spec/unit/logger_spec.rb +0 -14
- data/spec/unit/migration_tasks_spec.rb +0 -111
- data/spec/unit/migrator_spec.rb +0 -25
- data/spec/unit/order_dsl_spec.rb +0 -43
- data/spec/unit/plugin/associates_spec.rb +0 -94
- data/spec/unit/plugin/pagination_spec.rb +0 -91
- data/spec/unit/plugin/timestamp_spec.rb +0 -117
- data/spec/unit/projection_dsl_spec.rb +0 -110
- data/spec/unit/relation/assoc_spec.rb +0 -87
- data/spec/unit/relation/associations_spec.rb +0 -27
- data/spec/unit/relation/avg_spec.rb +0 -11
- data/spec/unit/relation/by_pk_spec.rb +0 -62
- data/spec/unit/relation/dataset_spec.rb +0 -50
- data/spec/unit/relation/distinct_spec.rb +0 -15
- data/spec/unit/relation/exclude_spec.rb +0 -11
- data/spec/unit/relation/exist_predicate_spec.rb +0 -25
- data/spec/unit/relation/exists_spec.rb +0 -18
- data/spec/unit/relation/fetch_spec.rb +0 -21
- data/spec/unit/relation/group_spec.rb +0 -61
- data/spec/unit/relation/having_spec.rb +0 -22
- data/spec/unit/relation/inner_join_spec.rb +0 -158
- data/spec/unit/relation/inspect_spec.rb +0 -11
- data/spec/unit/relation/instrument_spec.rb +0 -45
- data/spec/unit/relation/invert_spec.rb +0 -11
- data/spec/unit/relation/left_join_spec.rb +0 -55
- data/spec/unit/relation/lock_spec.rb +0 -93
- data/spec/unit/relation/map_spec.rb +0 -16
- data/spec/unit/relation/max_spec.rb +0 -11
- data/spec/unit/relation/min_spec.rb +0 -11
- data/spec/unit/relation/order_spec.rb +0 -51
- data/spec/unit/relation/pluck_spec.rb +0 -11
- data/spec/unit/relation/prefix_spec.rb +0 -29
- data/spec/unit/relation/primary_key_spec.rb +0 -27
- data/spec/unit/relation/project_spec.rb +0 -24
- data/spec/unit/relation/qualified_columns_spec.rb +0 -30
- data/spec/unit/relation/qualified_spec.rb +0 -25
- data/spec/unit/relation/read_spec.rb +0 -25
- data/spec/unit/relation/rename_spec.rb +0 -23
- data/spec/unit/relation/right_join_spec.rb +0 -57
- data/spec/unit/relation/select_append_spec.rb +0 -21
- data/spec/unit/relation/select_spec.rb +0 -40
- data/spec/unit/relation/sum_spec.rb +0 -11
- data/spec/unit/relation/union_spec.rb +0 -19
- data/spec/unit/relation/unique_predicate_spec.rb +0 -18
- data/spec/unit/relation/where_spec.rb +0 -133
- data/spec/unit/restriction_dsl_spec.rb +0 -34
- data/spec/unit/schema_spec.rb +0 -25
- data/spec/unit/types_spec.rb +0 -65
@@ -0,0 +1,21 @@
|
|
1
|
+
module ROM
|
2
|
+
module SQL
|
3
|
+
module Migration
|
4
|
+
# @api private
|
5
|
+
class Recorder
|
6
|
+
attr_reader :operations
|
7
|
+
|
8
|
+
def initialize(&block)
|
9
|
+
@operations = []
|
10
|
+
|
11
|
+
instance_exec(&block) if block
|
12
|
+
end
|
13
|
+
|
14
|
+
def method_missing(m, *args, &block)
|
15
|
+
nested = block ? Recorder.new(&block).operations : EMPTY_ARRAY
|
16
|
+
@operations << [m, args, nested]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module ROM
|
2
|
+
module SQL
|
3
|
+
module Migration
|
4
|
+
# @api private
|
5
|
+
class Runner
|
6
|
+
attr_reader :writer
|
7
|
+
|
8
|
+
def initialize(writer)
|
9
|
+
@writer = writer
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(changes)
|
13
|
+
changes.each { |diff| apply_schema(diff) }
|
14
|
+
changes.each { |diff| apply_constraints(diff) }
|
15
|
+
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def apply_schema(diff)
|
20
|
+
case diff
|
21
|
+
when SchemaDiff::TableCreated
|
22
|
+
create_table(diff)
|
23
|
+
when SchemaDiff::TableAltered
|
24
|
+
alter_table(diff)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def apply_constraints(diff)
|
29
|
+
case diff
|
30
|
+
when SchemaDiff::TableCreated
|
31
|
+
alter_foreign_keys(diff, diff.foreign_keys)
|
32
|
+
when SchemaDiff::TableAltered
|
33
|
+
alter_foreign_keys(diff, diff.foreign_key_changes)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_table(diff)
|
38
|
+
writer.migration do |connection|
|
39
|
+
connection.create_table(diff.table_name) do
|
40
|
+
diff.attributes.each do |attribute|
|
41
|
+
if attribute.primary_key?
|
42
|
+
primary_key attribute.name
|
43
|
+
else
|
44
|
+
column attribute.name, attribute.type, null: attribute.null?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
diff.indexes.each do |index|
|
49
|
+
index index.attributes, index.options
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def alter_table(diff)
|
56
|
+
return if diff.meta?
|
57
|
+
|
58
|
+
writer.migration do |connection|
|
59
|
+
connection.alter_table(diff.table_name) do
|
60
|
+
diff.attribute_changes.each do |attribute|
|
61
|
+
case attribute
|
62
|
+
when SchemaDiff::AttributeAdded
|
63
|
+
add_column attribute.name, attribute.type, null: attribute.null?
|
64
|
+
when SchemaDiff::AttributeRemoved
|
65
|
+
drop_column attribute.name
|
66
|
+
when SchemaDiff::AttributeChanged
|
67
|
+
if attribute.type_changed?
|
68
|
+
from, to = attribute.current.unwrap, attribute.target.unwrap
|
69
|
+
raise UnsupportedConversion.new(
|
70
|
+
"Don't know how to convert #{ from.inspect } to #{ to.inspect }"
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
if attribute.nullability_changed?
|
75
|
+
if attribute.null?
|
76
|
+
set_column_allow_null attribute.name
|
77
|
+
else
|
78
|
+
set_column_not_null attribute.name
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
diff.index_changes.each do |index|
|
85
|
+
case index
|
86
|
+
when SchemaDiff::IndexAdded
|
87
|
+
add_index index.attributes, index.options
|
88
|
+
when SchemaDiff::IndexRemoved
|
89
|
+
drop_index index.attributes, index.options
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def alter_foreign_keys(diff, foreign_key_changes)
|
97
|
+
return if foreign_key_changes.empty?
|
98
|
+
|
99
|
+
writer.migration do |connection|
|
100
|
+
connection.alter_table(diff.table_name) do
|
101
|
+
foreign_key_changes.map do |fk|
|
102
|
+
case fk
|
103
|
+
when SchemaDiff::ForeignKeyAdded
|
104
|
+
add_foreign_key fk.child_keys, fk.parent
|
105
|
+
when SchemaDiff::ForeignKeyRemoved
|
106
|
+
drop_foreign_key fk.child_keys
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -1,14 +1,22 @@
|
|
1
|
+
require 'rom/sql/type_serializer'
|
2
|
+
|
1
3
|
module ROM
|
2
4
|
module SQL
|
3
5
|
module Migration
|
6
|
+
# @api private
|
4
7
|
class SchemaDiff
|
8
|
+
extend Initializer
|
9
|
+
|
10
|
+
param :database_type
|
11
|
+
|
12
|
+
option :type_serializer, default: -> { ROM::SQL::TypeSerializer[database_type] }
|
13
|
+
|
5
14
|
class TableDiff
|
6
|
-
|
15
|
+
extend Initializer
|
7
16
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
17
|
+
option :current_schema, optional: true
|
18
|
+
|
19
|
+
option :target_schema, optional: true
|
12
20
|
|
13
21
|
def empty?
|
14
22
|
false
|
@@ -27,33 +35,33 @@ module ROM
|
|
27
35
|
|
28
36
|
class TableCreated < TableDiff
|
29
37
|
alias_method :schema, :target_schema
|
30
|
-
attr_reader :attributes, :indexes
|
31
38
|
|
32
|
-
|
33
|
-
super(rest)
|
39
|
+
option :attributes
|
34
40
|
|
35
|
-
|
36
|
-
|
37
|
-
|
41
|
+
option :indexes, default: -> { EMPTY_ARRAY }
|
42
|
+
|
43
|
+
option :foreign_keys, default: -> { EMPTY_ARRAY }
|
38
44
|
end
|
39
45
|
|
40
46
|
class TableAltered < TableDiff
|
41
|
-
attr_reader :attribute_changes, :index_changes
|
42
47
|
|
43
|
-
|
44
|
-
|
48
|
+
option :attribute_changes, default: -> { EMPTY_ARRAY }
|
49
|
+
|
50
|
+
option :index_changes, default: -> { EMPTY_ARRAY }
|
45
51
|
|
46
|
-
|
47
|
-
|
52
|
+
option :foreign_key_changes, default: -> { EMPTY_ARRAY }
|
53
|
+
|
54
|
+
def meta?
|
55
|
+
attribute_changes.empty? && index_changes.empty?
|
48
56
|
end
|
49
57
|
end
|
50
58
|
|
51
59
|
class AttributeDiff
|
52
|
-
|
60
|
+
extend Initializer
|
53
61
|
|
54
|
-
|
55
|
-
|
56
|
-
|
62
|
+
param :attr
|
63
|
+
|
64
|
+
option :type_serializer
|
57
65
|
|
58
66
|
def name
|
59
67
|
attr.name
|
@@ -74,7 +82,7 @@ module ROM
|
|
74
82
|
|
75
83
|
class AttributeAdded < AttributeDiff
|
76
84
|
def type
|
77
|
-
unwrap(attr).
|
85
|
+
type_serializer.(unwrap(attr).type)
|
78
86
|
end
|
79
87
|
end
|
80
88
|
|
@@ -82,25 +90,21 @@ module ROM
|
|
82
90
|
end
|
83
91
|
|
84
92
|
class AttributeChanged < AttributeDiff
|
85
|
-
|
93
|
+
param :current
|
86
94
|
alias_method :target, :attr
|
87
95
|
|
88
|
-
def initialize(current, target)
|
89
|
-
super(target)
|
90
|
-
|
91
|
-
@current = current
|
92
|
-
end
|
93
|
-
|
94
|
-
def to_a
|
95
|
-
[current, target]
|
96
|
-
end
|
97
|
-
|
98
96
|
def nullability_changed?
|
99
97
|
current.optional? ^ target.optional?
|
100
98
|
end
|
101
99
|
|
102
100
|
def type_changed?
|
103
|
-
|
101
|
+
clean(current.qualified) != clean(target.qualified)
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def clean(type)
|
107
|
+
unwrap(type).meta(index: nil, foreign_key: nil, target: nil)
|
104
108
|
end
|
105
109
|
end
|
106
110
|
|
@@ -112,55 +116,87 @@ module ROM
|
|
112
116
|
end
|
113
117
|
|
114
118
|
def attributes
|
115
|
-
index.attributes.map(&:name)
|
119
|
+
list = index.attributes.map(&:name)
|
120
|
+
|
121
|
+
if list.size == 1
|
122
|
+
list[0]
|
123
|
+
else
|
124
|
+
list
|
125
|
+
end
|
116
126
|
end
|
117
127
|
|
118
128
|
def name
|
119
129
|
index.name
|
120
130
|
end
|
131
|
+
end
|
121
132
|
|
122
|
-
|
123
|
-
|
133
|
+
class IndexAdded < IndexDiff
|
134
|
+
def options
|
135
|
+
options = {}
|
136
|
+
options[:name] = index.name if !index.name.nil?
|
137
|
+
options[:unique] = true if index.unique?
|
138
|
+
options[:type] = index.type if !index.type.nil?
|
139
|
+
options[:where] = index.predicate if !index.predicate.nil?
|
140
|
+
options
|
124
141
|
end
|
142
|
+
end
|
125
143
|
|
126
|
-
|
127
|
-
|
144
|
+
class IndexRemoved < IndexDiff
|
145
|
+
def options
|
146
|
+
options = {}
|
147
|
+
options[:name] = index.name if !index.name.nil?
|
148
|
+
options
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
class ForeignKeyDiff
|
153
|
+
attr_reader :foreign_key
|
154
|
+
|
155
|
+
def initialize(foreign_key)
|
156
|
+
@foreign_key = foreign_key
|
157
|
+
end
|
158
|
+
|
159
|
+
def parent
|
160
|
+
foreign_key.parent_table
|
128
161
|
end
|
129
162
|
|
130
|
-
def
|
131
|
-
|
163
|
+
def parent_keys
|
164
|
+
foreign_key.parent_keys
|
132
165
|
end
|
133
166
|
|
134
|
-
def
|
135
|
-
|
167
|
+
def child_keys
|
168
|
+
foreign_key.attributes.map(&:name)
|
136
169
|
end
|
137
170
|
end
|
138
171
|
|
139
|
-
class
|
172
|
+
class ForeignKeyAdded < ForeignKeyDiff
|
140
173
|
end
|
141
174
|
|
142
|
-
class
|
175
|
+
class ForeignKeyRemoved < ForeignKeyDiff
|
143
176
|
end
|
144
177
|
|
145
178
|
def call(current, target)
|
146
179
|
if current.empty?
|
147
180
|
TableCreated.new(
|
148
181
|
target_schema: target,
|
149
|
-
attributes: target.
|
150
|
-
indexes: target.indexes.map { |idx| IndexAdded.new(idx) }
|
182
|
+
attributes: map_attributes(target.to_h, AttributeAdded),
|
183
|
+
indexes: target.indexes.map { |idx| IndexAdded.new(idx) },
|
184
|
+
foreign_keys: target.foreign_keys.map { |fk| ForeignKeyAdded.new(fk) }
|
151
185
|
)
|
152
186
|
else
|
153
187
|
attribute_changes = compare_attributes(current.to_h, target.to_h)
|
154
188
|
index_changes = compare_indexes(current, target)
|
189
|
+
fk_changes = compare_foreign_key_constraints(current, target)
|
155
190
|
|
156
|
-
if attribute_changes.empty? && index_changes.empty?
|
191
|
+
if attribute_changes.empty? && index_changes.empty? && fk_changes.empty?
|
157
192
|
Empty.new(current_schema: current, target_schema: target)
|
158
193
|
else
|
159
194
|
TableAltered.new(
|
160
195
|
current_schema: current,
|
161
196
|
target_schema: target,
|
162
197
|
attribute_changes: attribute_changes,
|
163
|
-
index_changes: index_changes
|
198
|
+
index_changes: index_changes,
|
199
|
+
foreign_key_changes: fk_changes
|
164
200
|
)
|
165
201
|
end
|
166
202
|
end
|
@@ -168,16 +204,16 @@ module ROM
|
|
168
204
|
|
169
205
|
def compare_attributes(current, target)
|
170
206
|
changed_attributes = target.select { |name, attr|
|
171
|
-
current.key?(name) && current[name]
|
207
|
+
current.key?(name) && !attributes_equal?(current[name], attr)
|
172
208
|
}.map { |name, target_attr|
|
173
|
-
[name, [current[name]
|
209
|
+
[name, [target_attr, current[name]]]
|
174
210
|
}.to_h
|
175
211
|
added_attributes = target.select { |name, _| !current.key?(name) }
|
176
212
|
removed_attributes = current.select { |name, _| !target.key?(name) }
|
177
213
|
|
178
|
-
removed_attributes
|
179
|
-
added_attributes
|
180
|
-
changed_attributes
|
214
|
+
map_attributes(removed_attributes, AttributeRemoved) +
|
215
|
+
map_attributes(added_attributes, AttributeAdded) +
|
216
|
+
map_attributes(changed_attributes, AttributeChanged)
|
181
217
|
end
|
182
218
|
|
183
219
|
def compare_indexes(current, target)
|
@@ -191,6 +227,25 @@ module ROM
|
|
191
227
|
removed_indexes.map { |idx| IndexRemoved.new(idx) } +
|
192
228
|
added_indexes.map { |idx| IndexAdded.new(idx) }
|
193
229
|
end
|
230
|
+
|
231
|
+
def compare_foreign_key_constraints(current, target)
|
232
|
+
target_fks = target.foreign_keys
|
233
|
+
current_fks = current.foreign_keys
|
234
|
+
|
235
|
+
added_fks = target_fks - current_fks
|
236
|
+
removed_fks = current_fks - target_fks
|
237
|
+
|
238
|
+
removed_fks.map { |fk| ForeignKeyRemoved.new(fk) } +
|
239
|
+
added_fks.map { |fk| ForeignKeyAdded.new(fk) }
|
240
|
+
end
|
241
|
+
|
242
|
+
def attributes_equal?(a, b)
|
243
|
+
a.qualified == b.qualified
|
244
|
+
end
|
245
|
+
|
246
|
+
def map_attributes(attributes, change_type)
|
247
|
+
attributes.values.map { |args| change_type.new(*args, type_serializer: type_serializer) }
|
248
|
+
end
|
194
249
|
end
|
195
250
|
end
|
196
251
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'rom/sql/migration/recorder'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
module SQL
|
5
|
+
module Migration
|
6
|
+
# @api private
|
7
|
+
class Writer
|
8
|
+
MIGRATION_BEGIN = "ROM::SQL.migration do\n change do".freeze
|
9
|
+
MIGRATION_END = "\n end\nend\n".freeze
|
10
|
+
|
11
|
+
attr_reader :yield_migration
|
12
|
+
|
13
|
+
def initialize(&block)
|
14
|
+
@yield_migration = block
|
15
|
+
end
|
16
|
+
|
17
|
+
def migration
|
18
|
+
recorder = Recorder.new
|
19
|
+
yield(recorder)
|
20
|
+
yield_migration.(create_migration(recorder.operations))
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_migration(ops)
|
24
|
+
out = MIGRATION_BEGIN.dup
|
25
|
+
write(ops, out, "\n ")
|
26
|
+
out << MIGRATION_END
|
27
|
+
|
28
|
+
[migration_name(ops[0]), out]
|
29
|
+
end
|
30
|
+
|
31
|
+
def write(operations, buffer, indent)
|
32
|
+
operations.each do |operation|
|
33
|
+
op, args, nested = operation
|
34
|
+
buffer << indent << op.to_s << ' '
|
35
|
+
write_arguments(buffer, *args)
|
36
|
+
|
37
|
+
if !nested.empty?
|
38
|
+
buffer << ' do'
|
39
|
+
write(nested, buffer, indent + ' ')
|
40
|
+
buffer << indent << 'end'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def write_arguments(buffer, *args, **kwargs)
|
46
|
+
buffer << args.map(&:inspect).join(', ')
|
47
|
+
kwargs.each do |key, value|
|
48
|
+
buffer << ', ' << key.to_s << ': ' << value.inspect
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def migration_name(op)
|
53
|
+
create_or_alter, args = op
|
54
|
+
table_name = args[0]
|
55
|
+
|
56
|
+
"#{ create_or_alter.to_s.sub('_table', '') }_#{ table_name }"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|