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.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -0
  3. data/lib/rom/plugins/relation/sql/postgres/explain.rb +54 -0
  4. data/lib/rom/sql.rb +1 -1
  5. data/lib/rom/sql/attribute.rb +17 -18
  6. data/lib/rom/sql/errors.rb +3 -0
  7. data/lib/rom/sql/extensions/mysql.rb +1 -1
  8. data/lib/rom/sql/extensions/mysql/type_builder.rb +28 -0
  9. data/lib/rom/sql/extensions/postgres.rb +3 -1
  10. data/lib/rom/sql/extensions/postgres/commands.rb +30 -13
  11. data/lib/rom/sql/extensions/postgres/{attributes_inferrer.rb → type_builder.rb} +24 -28
  12. data/lib/rom/sql/extensions/postgres/type_serializer.rb +39 -0
  13. data/lib/rom/sql/extensions/postgres/types.rb +24 -477
  14. data/lib/rom/sql/extensions/postgres/types/array.rb +163 -0
  15. data/lib/rom/sql/extensions/postgres/types/geometric.rb +135 -0
  16. data/lib/rom/sql/extensions/postgres/types/json.rb +235 -0
  17. data/lib/rom/sql/extensions/postgres/types/network.rb +15 -0
  18. data/lib/rom/sql/extensions/sqlite.rb +1 -1
  19. data/lib/rom/sql/extensions/sqlite/{attributes_inferrer.rb → type_builder.rb} +5 -5
  20. data/lib/rom/sql/extensions/sqlite/types.rb +8 -3
  21. data/lib/rom/sql/foreign_key.rb +17 -0
  22. data/lib/rom/sql/function.rb +86 -8
  23. data/lib/rom/sql/gateway.rb +26 -26
  24. data/lib/rom/sql/index.rb +4 -0
  25. data/lib/rom/sql/migration.rb +3 -3
  26. data/lib/rom/sql/migration/inline_runner.rb +9 -83
  27. data/lib/rom/sql/migration/migrator.rb +35 -12
  28. data/lib/rom/sql/migration/recorder.rb +21 -0
  29. data/lib/rom/sql/migration/runner.rb +115 -0
  30. data/lib/rom/sql/migration/schema_diff.rb +108 -53
  31. data/lib/rom/sql/migration/writer.rb +61 -0
  32. data/lib/rom/sql/relation.rb +2 -1
  33. data/lib/rom/sql/relation/reading.rb +63 -3
  34. data/lib/rom/sql/relation/writing.rb +38 -0
  35. data/lib/rom/sql/schema.rb +9 -3
  36. data/lib/rom/sql/schema/attributes_inferrer.rb +3 -119
  37. data/lib/rom/sql/schema/inferrer.rb +99 -18
  38. data/lib/rom/sql/schema/type_builder.rb +94 -0
  39. data/lib/rom/sql/type_dsl.rb +30 -0
  40. data/lib/rom/sql/type_extensions.rb +11 -6
  41. data/lib/rom/sql/type_serializer.rb +46 -0
  42. data/lib/rom/sql/types.rb +12 -0
  43. data/lib/rom/sql/version.rb +1 -1
  44. metadata +26 -244
  45. data/.codeclimate.yml +0 -15
  46. data/.gitignore +0 -17
  47. data/.rspec +0 -3
  48. data/.travis.yml +0 -39
  49. data/.yardopts +0 -2
  50. data/Gemfile +0 -33
  51. data/Guardfile +0 -24
  52. data/LICENSE.txt +0 -22
  53. data/Rakefile +0 -19
  54. data/circle.yml +0 -10
  55. data/lib/rom/sql/extensions/mysql/attributes_inferrer.rb +0 -10
  56. data/lib/rom/sql/relation/sequel_api.rb +0 -133
  57. data/log/.gitkeep +0 -0
  58. data/rom-sql.gemspec +0 -29
  59. data/spec/extensions/postgres/attribute_spec.rb +0 -217
  60. data/spec/extensions/postgres/integration_spec.rb +0 -59
  61. data/spec/extensions/postgres/types_spec.rb +0 -252
  62. data/spec/extensions/sqlite/types_spec.rb +0 -11
  63. data/spec/fixtures/migrations/20150403090603_create_carrots.rb +0 -8
  64. data/spec/integration/associations/many_to_many/custom_fks_spec.rb +0 -76
  65. data/spec/integration/associations/many_to_many/from_view_spec.rb +0 -88
  66. data/spec/integration/associations/many_to_many_spec.rb +0 -162
  67. data/spec/integration/associations/many_to_one/custom_fks_spec.rb +0 -64
  68. data/spec/integration/associations/many_to_one/from_view_spec.rb +0 -84
  69. data/spec/integration/associations/many_to_one/self_ref_spec.rb +0 -53
  70. data/spec/integration/associations/many_to_one_spec.rb +0 -117
  71. data/spec/integration/associations/one_to_many/custom_fks_spec.rb +0 -54
  72. data/spec/integration/associations/one_to_many/from_view_spec.rb +0 -57
  73. data/spec/integration/associations/one_to_many/self_ref_spec.rb +0 -54
  74. data/spec/integration/associations/one_to_many_spec.rb +0 -86
  75. data/spec/integration/associations/one_to_one_spec.rb +0 -69
  76. data/spec/integration/associations/one_to_one_through_spec.rb +0 -92
  77. data/spec/integration/auto_migrations/errors_spec.rb +0 -31
  78. data/spec/integration/auto_migrations/indexes_spec.rb +0 -253
  79. data/spec/integration/auto_migrations/managing_columns_spec.rb +0 -156
  80. data/spec/integration/auto_migrations/postgres/column_types_spec.rb +0 -63
  81. data/spec/integration/combine_with_spec.rb +0 -43
  82. data/spec/integration/commands/create_spec.rb +0 -304
  83. data/spec/integration/commands/delete_spec.rb +0 -84
  84. data/spec/integration/commands/update_spec.rb +0 -90
  85. data/spec/integration/commands/upsert_spec.rb +0 -83
  86. data/spec/integration/gateway_spec.rb +0 -107
  87. data/spec/integration/migration_spec.rb +0 -55
  88. data/spec/integration/plugins/associates/many_to_many_spec.rb +0 -69
  89. data/spec/integration/plugins/associates_spec.rb +0 -250
  90. data/spec/integration/plugins/auto_restrictions_spec.rb +0 -74
  91. data/spec/integration/relation_schema_spec.rb +0 -271
  92. data/spec/integration/schema/call_spec.rb +0 -24
  93. data/spec/integration/schema/inferrer/mysql_spec.rb +0 -45
  94. data/spec/integration/schema/inferrer/postgres_spec.rb +0 -203
  95. data/spec/integration/schema/inferrer/sqlite_spec.rb +0 -37
  96. data/spec/integration/schema/inferrer_spec.rb +0 -390
  97. data/spec/integration/schema/prefix_spec.rb +0 -16
  98. data/spec/integration/schema/qualified_spec.rb +0 -16
  99. data/spec/integration/schema/rename_spec.rb +0 -21
  100. data/spec/integration/schema/view_spec.rb +0 -29
  101. data/spec/integration/sequel_api_spec.rb +0 -36
  102. data/spec/integration/setup_spec.rb +0 -26
  103. data/spec/integration/support/active_support_notifications_spec.rb +0 -24
  104. data/spec/integration/support/rails_log_subscriber_spec.rb +0 -30
  105. data/spec/integration/wrap_spec.rb +0 -91
  106. data/spec/shared/accounts.rb +0 -48
  107. data/spec/shared/database_setup.rb +0 -70
  108. data/spec/shared/notes.rb +0 -23
  109. data/spec/shared/posts.rb +0 -34
  110. data/spec/shared/puppies.rb +0 -15
  111. data/spec/shared/relations.rb +0 -8
  112. data/spec/shared/users.rb +0 -32
  113. data/spec/shared/users_and_tasks.rb +0 -50
  114. data/spec/spec_helper.rb +0 -122
  115. data/spec/support/env_helper.rb +0 -25
  116. data/spec/support/helpers.rb +0 -24
  117. data/spec/support/oracle/create_users.sql +0 -7
  118. data/spec/support/oracle/set_sys_passwords.sql +0 -2
  119. data/spec/support/test_configuration.rb +0 -16
  120. data/spec/unit/attribute_spec.rb +0 -104
  121. data/spec/unit/function_spec.rb +0 -48
  122. data/spec/unit/gateway_spec.rb +0 -70
  123. data/spec/unit/logger_spec.rb +0 -14
  124. data/spec/unit/migration_tasks_spec.rb +0 -111
  125. data/spec/unit/migrator_spec.rb +0 -25
  126. data/spec/unit/order_dsl_spec.rb +0 -43
  127. data/spec/unit/plugin/associates_spec.rb +0 -94
  128. data/spec/unit/plugin/pagination_spec.rb +0 -91
  129. data/spec/unit/plugin/timestamp_spec.rb +0 -117
  130. data/spec/unit/projection_dsl_spec.rb +0 -110
  131. data/spec/unit/relation/assoc_spec.rb +0 -87
  132. data/spec/unit/relation/associations_spec.rb +0 -27
  133. data/spec/unit/relation/avg_spec.rb +0 -11
  134. data/spec/unit/relation/by_pk_spec.rb +0 -62
  135. data/spec/unit/relation/dataset_spec.rb +0 -50
  136. data/spec/unit/relation/distinct_spec.rb +0 -15
  137. data/spec/unit/relation/exclude_spec.rb +0 -11
  138. data/spec/unit/relation/exist_predicate_spec.rb +0 -25
  139. data/spec/unit/relation/exists_spec.rb +0 -18
  140. data/spec/unit/relation/fetch_spec.rb +0 -21
  141. data/spec/unit/relation/group_spec.rb +0 -61
  142. data/spec/unit/relation/having_spec.rb +0 -22
  143. data/spec/unit/relation/inner_join_spec.rb +0 -158
  144. data/spec/unit/relation/inspect_spec.rb +0 -11
  145. data/spec/unit/relation/instrument_spec.rb +0 -45
  146. data/spec/unit/relation/invert_spec.rb +0 -11
  147. data/spec/unit/relation/left_join_spec.rb +0 -55
  148. data/spec/unit/relation/lock_spec.rb +0 -93
  149. data/spec/unit/relation/map_spec.rb +0 -16
  150. data/spec/unit/relation/max_spec.rb +0 -11
  151. data/spec/unit/relation/min_spec.rb +0 -11
  152. data/spec/unit/relation/order_spec.rb +0 -51
  153. data/spec/unit/relation/pluck_spec.rb +0 -11
  154. data/spec/unit/relation/prefix_spec.rb +0 -29
  155. data/spec/unit/relation/primary_key_spec.rb +0 -27
  156. data/spec/unit/relation/project_spec.rb +0 -24
  157. data/spec/unit/relation/qualified_columns_spec.rb +0 -30
  158. data/spec/unit/relation/qualified_spec.rb +0 -25
  159. data/spec/unit/relation/read_spec.rb +0 -25
  160. data/spec/unit/relation/rename_spec.rb +0 -23
  161. data/spec/unit/relation/right_join_spec.rb +0 -57
  162. data/spec/unit/relation/select_append_spec.rb +0 -21
  163. data/spec/unit/relation/select_spec.rb +0 -40
  164. data/spec/unit/relation/sum_spec.rb +0 -11
  165. data/spec/unit/relation/union_spec.rb +0 -19
  166. data/spec/unit/relation/unique_predicate_spec.rb +0 -18
  167. data/spec/unit/relation/where_spec.rb +0 -133
  168. data/spec/unit/restriction_dsl_spec.rb +0 -34
  169. data/spec/unit/schema_spec.rb +0 -25
  170. 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
- attr_reader :current_schema, :target_schema
15
+ extend Initializer
7
16
 
8
- def initialize(current_schema: nil, target_schema: nil)
9
- @current_schema = current_schema
10
- @target_schema = target_schema
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
- def initialize(attributes:, indexes: EMPTY_ARRAY, **rest)
33
- super(rest)
39
+ option :attributes
34
40
 
35
- @attributes = attributes
36
- @indexes = indexes
37
- end
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
- def initialize(attribute_changes: EMPTY_ARRAY, index_changes: EMPTY_ARRAY, **rest)
44
- super(rest)
48
+ option :attribute_changes, default: -> { EMPTY_ARRAY }
49
+
50
+ option :index_changes, default: -> { EMPTY_ARRAY }
45
51
 
46
- @attribute_changes = attribute_changes
47
- @index_changes = index_changes
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
- attr_reader :attr
60
+ extend Initializer
53
61
 
54
- def initialize(attr)
55
- @attr = attr
56
- end
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).primitive
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
- attr_reader :current
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
- unwrap(current).meta(index: Set.new) != unwrap(target).meta(index: Set.new)
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
- def unique?
123
- index.unique?
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
- def type
127
- index.type
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 predicate
131
- index.predicate
163
+ def parent_keys
164
+ foreign_key.parent_keys
132
165
  end
133
166
 
134
- def partial?
135
- !predicate.nil?
167
+ def child_keys
168
+ foreign_key.attributes.map(&:name)
136
169
  end
137
170
  end
138
171
 
139
- class IndexAdded < IndexDiff
172
+ class ForeignKeyAdded < ForeignKeyDiff
140
173
  end
141
174
 
142
- class IndexRemoved < IndexDiff
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.map { |attr| AttributeAdded.new(attr) },
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] != attr
207
+ current.key?(name) && !attributes_equal?(current[name], attr)
172
208
  }.map { |name, target_attr|
173
- [name, [current[name], target_attr]]
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.values.map { |attr| AttributeRemoved.new(attr) } +
179
- added_attributes.values.map { |attr| AttributeAdded.new(attr) } +
180
- changed_attributes.values.map { |attrs| AttributeChanged.new(*attrs) }
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