rom-sql 2.0.0.beta2 → 2.0.0.beta3
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 +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
|