cequel 2.1.0 → 3.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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/Gemfile.lock +2 -2
  4. data/README.md +8 -0
  5. data/lib/cequel/errors.rb +2 -0
  6. data/lib/cequel/metal/new_relic_instrumentation.rb +2 -1
  7. data/lib/cequel/record.rb +8 -0
  8. data/lib/cequel/record/schema.rb +30 -23
  9. data/lib/cequel/schema.rb +3 -2
  10. data/lib/cequel/schema/column.rb +11 -1
  11. data/lib/cequel/schema/keyspace.rb +18 -7
  12. data/lib/cequel/schema/patch.rb +152 -0
  13. data/lib/cequel/schema/table.rb +55 -137
  14. data/lib/cequel/schema/table_desc_dsl.rb +196 -0
  15. data/lib/cequel/schema/table_differ.rb +112 -0
  16. data/lib/cequel/schema/table_property.rb +14 -0
  17. data/lib/cequel/schema/table_reader.rb +81 -85
  18. data/lib/cequel/schema/table_updater.rb +0 -17
  19. data/lib/cequel/schema/table_writer.rb +10 -9
  20. data/lib/cequel/version.rb +1 -1
  21. data/spec/examples/metal/data_set_spec.rb +156 -153
  22. data/spec/examples/metal/keyspace_spec.rb +4 -4
  23. data/spec/examples/record/associations_spec.rb +6 -0
  24. data/spec/examples/record/mass_assignment_spec.rb +2 -2
  25. data/spec/examples/record/properties_spec.rb +1 -0
  26. data/spec/examples/record/record_set_spec.rb +1 -1
  27. data/spec/examples/schema/patch_spec.rb +190 -0
  28. data/spec/examples/schema/table_differ_spec.rb +280 -0
  29. data/spec/examples/schema/table_reader_spec.rb +379 -354
  30. data/spec/examples/schema/table_updater_spec.rb +0 -12
  31. data/spec/examples/spec_helper.rb +5 -5
  32. data/spec/examples/spec_support/preparation_spec.rb +4 -0
  33. data/spec/support/helpers.rb +23 -0
  34. metadata +9 -6
  35. data/lib/cequel/schema/create_table_dsl.rb +0 -88
  36. data/lib/cequel/schema/table_synchronizer.rb +0 -180
  37. data/spec/examples/schema/table_synchronizer_spec.rb +0 -200
@@ -86,17 +86,17 @@ describe Cequel::Metal::Keyspace do
86
86
  end
87
87
  end
88
88
 
89
- describe "#drop_table", cassandra: '~> 3.x' do
89
+ describe "#drop_table", cql: "~> 3.1" do
90
90
  it "allows IF EXISTS" do
91
91
  expect { cequel.schema.drop_table(:unknown) }.to raise_error(Cassandra::Errors::InvalidError)
92
- expect { cequel.schema.drop_table(:unknown, exists: true) }.not_to raise_error(Cassandra::Errors::InvalidError)
92
+ expect { cequel.schema.drop_table(:unknown, exists: true) }.not_to raise_error
93
93
  end
94
94
  end
95
95
 
96
- describe "#drop_materialized_view", cassandra: '~> 3.x' do
96
+ describe "#drop_materialized_view", cql: "~> 3.4" do
97
97
  it "allows IF EXISTS" do
98
98
  expect { cequel.schema.drop_materialized_view(:unknown) }.to raise_error(Cassandra::Errors::ConfigurationError)
99
- expect { cequel.schema.drop_materialized_view(:unknown, exists: true) }.not_to raise_error(Cassandra::Errors::ConfigurationError)
99
+ expect { cequel.schema.drop_materialized_view(:unknown, exists: true) }.not_to raise_error
100
100
  end
101
101
  end
102
102
 
@@ -104,6 +104,7 @@ describe Cequel::Record::Associations do
104
104
  expect do
105
105
  Class.new do
106
106
  include Cequel::Record
107
+ self.table_name = "foo"
107
108
  key :permalink, :text
108
109
  belongs_to :blog
109
110
  end
@@ -114,6 +115,7 @@ describe Cequel::Record::Associations do
114
115
  expect do
115
116
  Class.new do
116
117
  include Cequel::Record
118
+ self.table_name = "foo"
117
119
  belongs_to :blog
118
120
  belongs_to :user
119
121
  end
@@ -169,6 +171,8 @@ describe Cequel::Record::Associations do
169
171
  expect do
170
172
  Class.new do
171
173
  include Cequel::Record
174
+ self.table_name = "foo"
175
+
172
176
  key :permalink, :text
173
177
  belongs_to :post, partition: true
174
178
  end
@@ -179,6 +183,8 @@ describe Cequel::Record::Associations do
179
183
  expect do
180
184
  Class.new do
181
185
  include Cequel::Record
186
+ self.table_name = "foo"
187
+
182
188
  belongs_to :post, partition: true
183
189
  belongs_to :user
184
190
  end
@@ -2,7 +2,7 @@
2
2
  require_relative 'spec_helper'
3
3
 
4
4
  describe Cequel::Record::MassAssignment do
5
- context 'with strong parameters', :rails => '~> 4.0' do
5
+ context 'with strong parameters', rails: '>= 4.0' do
6
6
  model :Post do
7
7
  key :permalink, :text
8
8
  column :title, :text
@@ -34,7 +34,7 @@ describe Cequel::Record::MassAssignment do
34
34
  end
35
35
  end
36
36
 
37
- context 'with mass-assignment protection', :rails => '~> 3.1' do
37
+ context 'with mass-assignment protection', rails: '~> 3.0' do
38
38
  model :Post do
39
39
  key :permalink, :text
40
40
  column :title, :text
@@ -203,6 +203,7 @@ describe Cequel::Record::Properties do
203
203
  expect do
204
204
  Class.new do
205
205
  include Cequel::Record
206
+ self.table_name = "foo"
206
207
  key :subdomain, :text, auto: true
207
208
  end
208
209
  end.to raise_error(ArgumentError)
@@ -806,7 +806,7 @@ describe Cequel::Record::RecordSet do
806
806
  end
807
807
  end
808
808
 
809
- context 'allow_filtering!', cassandra: '~> 3.x' do
809
+ context 'allow_filtering!', cql: '~> 3.4' do
810
810
  it 'should allow filtering for none indexed columns' do
811
811
  expect(Post.allow_filtering!.where(title: 'Cequel 0').entries.length).to be(1)
812
812
  end
@@ -0,0 +1,190 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require File.expand_path('../../spec_helper', __FILE__)
3
+
4
+ module Cequel::Schema
5
+ describe Patch do
6
+
7
+ let(:table_name) { |ex| unique_table_name("posts", ex) }
8
+ let(:table) {
9
+ Table.new(table_name).tap do |t|
10
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
11
+ end
12
+ }
13
+
14
+ describe ".new" do
15
+ it "returns a Patch" do
16
+ expect(
17
+ described_class.new([])
18
+ ).to be_kind_of described_class
19
+ end
20
+ end
21
+
22
+ describe "#changes" do
23
+ context "no changes" do
24
+ subject { described_class.new([]) }
25
+
26
+ it "returns the changes" do
27
+ expect( subject.changes ).to be_empty
28
+ end
29
+ end
30
+
31
+ context "no some changes" do
32
+ let(:change) {
33
+ Patch::AddColumn.new(table, DataColumn.new(:author_name, Cequel::Type[:text]))
34
+ }
35
+
36
+ subject { described_class.new([change]) }
37
+
38
+ it "returns the changes" do
39
+ expect( subject.changes ).to eq [change]
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "#statements" do
45
+ let(:change) {
46
+ Patch::AddColumn.new(table, DataColumn.new(:author_name, Cequel::Type[:text]))
47
+ }
48
+
49
+ subject { described_class.new([change]) }
50
+
51
+ it "returns a statement for each change" do
52
+ expect( subject.statements.count ).to eq subject.changes.count
53
+ expect( subject.statements.count ).to eq 1
54
+ end
55
+ end
56
+ end
57
+
58
+ describe Patch::SetTableProperties do
59
+ let(:table_name) { |ex| unique_table_name("posts", ex) }
60
+ let(:table) {
61
+ Table.new(table_name).tap do |t|
62
+ t.add_property TableProperty.build(:comment, "hello")
63
+ end
64
+ }
65
+
66
+ describe "#new" do
67
+ it "returns #{described_class}" do
68
+ expect( described_class.new(table) ).to be_kind_of described_class
69
+ end
70
+ end
71
+
72
+ subject { described_class.new(table) }
73
+
74
+ describe "#to_cql" do
75
+ it "sets the property" do
76
+ expect( subject.to_cql ).to match /alter +table +"?#{table_name}"? +with/i
77
+ expect( subject.to_cql ).to match /"?comment"? *= *'hello'/i
78
+ end
79
+ end
80
+
81
+ describe "#properties" do
82
+ it "returns collection of Table properties to be set" do
83
+ expect( subject.properties ).to all be_kind_of TableProperty
84
+ expect( subject.properties ).to eq table.properties.values
85
+ end
86
+
87
+ end
88
+ end
89
+
90
+ describe Patch::DropIndex do
91
+ let(:table_name) { |ex| unique_table_name("posts", ex) }
92
+ let(:table) { Table.new(table_name) }
93
+ let(:column_with_obsolete_idx) {
94
+ DataColumn.new(:author_name, Cequel::Type[:text], :author_name_idx)
95
+ }
96
+
97
+ describe "#new" do
98
+ it "returns #{described_class}" do
99
+ expect(
100
+ described_class.new(table, column_with_obsolete_idx)
101
+ ).to be_kind_of described_class
102
+ end
103
+ end
104
+
105
+ subject { described_class.new(table, column_with_obsolete_idx) }
106
+
107
+ describe "#to_cql" do
108
+ it "drops index" do
109
+ expect( subject.to_cql ).to match /drop +index/i
110
+ expect( subject.to_cql ).to match /"?#{column_with_obsolete_idx.index_name}"?/i
111
+ end
112
+ end
113
+
114
+ describe "#index_name" do
115
+ it "returns the index name" do
116
+ expect( subject.index_name ).to eq column_with_obsolete_idx.index_name
117
+ end
118
+ end
119
+ end
120
+
121
+ describe Patch::AddIndex do
122
+ let(:table_name) { |ex| unique_table_name("posts", ex) }
123
+ let(:table) { Table.new(table_name) }
124
+ let(:column) {
125
+ DataColumn.new(:author_name, Cequel::Type[:text], :author_name_idx)
126
+ }
127
+
128
+ describe "#new" do
129
+ it "returns #{described_class}" do
130
+ expect(
131
+ described_class.new(table, column)
132
+ ).to be_kind_of described_class
133
+ end
134
+ end
135
+
136
+ subject { described_class.new(table, column) }
137
+
138
+ describe "#to_cql" do
139
+ it "creates the index" do
140
+ expect( subject.to_cql ).to match /create +index/i
141
+ expect( subject.to_cql ).to match /"#{column.index_name}"/i
142
+ expect( subject.to_cql ).to match /( *"#{column.name}" *)/i
143
+ end
144
+ end
145
+
146
+ describe "#index_name" do
147
+ it "returns the index name" do
148
+ expect( subject.index_name ).to eq column.index_name
149
+ end
150
+ end
151
+
152
+ describe "#column" do
153
+ it "returns the column" do
154
+ expect( subject.column ).to eq column
155
+ end
156
+ end
157
+ end
158
+
159
+ describe Patch::AddColumn do
160
+ let(:table_name) { |ex| unique_table_name("posts", ex) }
161
+ let(:table) { Table.new(table_name) }
162
+ let(:column) {
163
+ DataColumn.new(:author_name, Cequel::Type[:text])
164
+ }
165
+
166
+ describe "#new" do
167
+ it "returns #{described_class}" do
168
+ expect(
169
+ described_class.new(table, column)
170
+ ).to be_kind_of described_class
171
+ end
172
+ end
173
+
174
+ subject { described_class.new(table, column) }
175
+
176
+ describe "#to_cql" do
177
+ it "adds the column" do
178
+ expect( subject.to_cql ).to match /alter +table/i
179
+ expect( subject.to_cql ).to match /"#{table_name}"/i
180
+ expect( subject.to_cql ).to match /add +"#{column.name}"/i
181
+ end
182
+ end
183
+
184
+ describe "#column" do
185
+ it "returns the column" do
186
+ expect( subject.column ).to eq column
187
+ end
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,280 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require File.expand_path('../../spec_helper', __FILE__)
3
+
4
+ module Cequel::Schema
5
+ describe TableDiffer do
6
+
7
+ let(:table_name) { |ex| unique_table_name("posts", ex) }
8
+ let(:orig_table) {
9
+ Table.new(table_name).tap do |t|
10
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
11
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text])
12
+ t.add_column DataColumn.new(:body, Cequel::Type[:text])
13
+ t.add_column DataColumn.new(:author_name, Cequel::Type[:text], :author_name_idx)
14
+ t.add_property TableProperty.build(:comment, "Orig comment")
15
+ end
16
+ }
17
+
18
+ describe ".new" do
19
+ it "returns a TableDiffer" do
20
+ expect(
21
+ described_class.new(orig_table, orig_table)
22
+ ).to be_kind_of described_class
23
+ end
24
+ end
25
+
26
+ describe ".call" do
27
+ it "returns a Patch" do
28
+ updated_table = Table.new(table_name).tap do |t|
29
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
30
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text])
31
+ t.add_column DataColumn.new(:body, Cequel::Type[:text])
32
+ t.add_column DataColumn.new(:author_name, Cequel::Type[:text], :author_name_idx)
33
+ t.add_property TableProperty.build(:comment, "Orig comment")
34
+ end
35
+
36
+ expect(
37
+ described_class.new(orig_table, updated_table).call
38
+ ).to be_kind_of Patch
39
+ end
40
+
41
+ it "fails for table name changes" do
42
+ renamed_table = Table.new(:fancy_new_name).tap do |t|
43
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
44
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text])
45
+ t.add_column DataColumn.new(:body, Cequel::Type[:text])
46
+ t.add_column DataColumn.new(:author_name, Cequel::Type[:text], :author_name_idx)
47
+ t.add_property TableProperty.build(:comment, "Orig comment")
48
+ end
49
+
50
+ expect{
51
+ described_class.new(orig_table, renamed_table).call
52
+ }.to raise_error(Cequel::InvalidSchemaMigration)
53
+ end
54
+
55
+ it "succeed if name difference it immaterial" do
56
+ equiv_table = Table.new(table_name.to_s).tap do |t|
57
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
58
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text])
59
+ t.add_column DataColumn.new(:body, Cequel::Type[:text])
60
+ t.add_column DataColumn.new(:author_name, Cequel::Type[:text], :author_name_idx)
61
+ t.add_property TableProperty.build(:comment, "Orig comment")
62
+ end
63
+
64
+ expect{
65
+ described_class.new(orig_table, equiv_table).call
66
+ }.not_to raise_error
67
+ end
68
+
69
+ it "fails for type changes" do
70
+ updated_table = Table.new(table_name).tap do |t|
71
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
72
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text])
73
+ t.add_column DataColumn.new(:body, Cequel::Type[:ascii])
74
+ end
75
+
76
+ expect{
77
+ described_class.new(orig_table, updated_table).call
78
+ }.to raise_error(Cequel::InvalidSchemaMigration)
79
+ end
80
+
81
+ it "fails for partition key changes" do
82
+ updated_table = Table.new(table_name).tap do |t|
83
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
84
+ t.add_column PartitionKey.new(:date, Cequel::Type[:timestamp])
85
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text])
86
+ t.add_column DataColumn.new(:body, Cequel::Type[:text])
87
+ t.add_column DataColumn.new(:author_name, Cequel::Type[:text], :author_name_idx)
88
+ t.add_property TableProperty.build(:comment, "Orig comment")
89
+ end
90
+
91
+ expect{
92
+ described_class.new(orig_table, updated_table).call
93
+ }.to raise_error(Cequel::InvalidSchemaMigration)
94
+ end
95
+
96
+ it "fails for clustering order changes" do
97
+ updated_table = Table.new(table_name).tap do |t|
98
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
99
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text], :desc)
100
+ t.add_column DataColumn.new(:body, Cequel::Type[:text])
101
+ t.add_column DataColumn.new(:author_name, Cequel::Type[:text], :author_name_idx)
102
+ t.add_property TableProperty.build(:comment, "Orig comment")
103
+ end
104
+
105
+ expect{
106
+ described_class.new(orig_table, updated_table).call
107
+ }.to raise_error(Cequel::InvalidSchemaMigration)
108
+ end
109
+
110
+ it "ignore immaterial changes to clustering order" do
111
+ unchanged_table = Table.new(table_name).tap do |t|
112
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
113
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text], :asc)
114
+ t.add_column DataColumn.new(:body, Cequel::Type[:text])
115
+ t.add_column DataColumn.new(:author_name, Cequel::Type[:text], :author_name_idx)
116
+ t.add_property TableProperty.build(:comment, "Orig comment")
117
+ end
118
+
119
+ expect{
120
+ described_class.new(orig_table, unchanged_table).call
121
+ }.not_to raise_error
122
+ end
123
+
124
+ it "detects a lack of changes changes" do
125
+ unchanged_table = Table.new(table_name).tap do |t|
126
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
127
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text])
128
+ t.add_column DataColumn.new(:body, Cequel::Type[:text])
129
+ t.add_column DataColumn.new(:author_name, Cequel::Type[:text], :author_name_idx)
130
+ t.add_property TableProperty.build(:comment, "Orig comment")
131
+ end
132
+
133
+ expect(
134
+ described_class.new(orig_table, unchanged_table).call
135
+ ).to be_empty
136
+ end
137
+
138
+ it "detects new columns" do
139
+ updated_table = Table.new(table_name).tap do |t|
140
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
141
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text])
142
+ t.add_column DataColumn.new(:body, Cequel::Type[:text])
143
+ t.add_column DataColumn.new(:created_at, Cequel::Type[:timestamp])
144
+ end
145
+
146
+ expect(
147
+ described_class.new(orig_table, updated_table).call
148
+ ).to add_column(:created_at).of_type(:timestamp)
149
+ end
150
+
151
+ it "detects added index to existing column" do
152
+ updated_table = Table.new(table_name).tap do |t|
153
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
154
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text])
155
+ t.add_column DataColumn.new(:body, Cequel::Type[:text], :my_index_name)
156
+ end
157
+
158
+ expect(
159
+ described_class.new(orig_table, updated_table).call
160
+ ).to add_index(:my_index_name).of_column(:body)
161
+ end
162
+
163
+ it "detects dropped index" do
164
+ updated_table = Table.new(table_name).tap do |t|
165
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
166
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text])
167
+ t.add_column DataColumn.new(:body, Cequel::Type[:text])
168
+ t.add_column DataColumn.new(:author_name, Cequel::Type[:text])
169
+ end
170
+
171
+ expect(
172
+ described_class.new(orig_table, updated_table).call
173
+ ).to drop_index(:author_name_idx)
174
+ end
175
+
176
+ it "detects added index to new column" do
177
+ updated_table = Table.new(table_name).tap do |t|
178
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
179
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text])
180
+ t.add_column DataColumn.new(:category, Cequel::Type[:text], :posts_category_idx)
181
+ end
182
+
183
+ expect(
184
+ described_class.new(orig_table, updated_table).call
185
+ ).to add_index(:posts_category_idx).of_column(:category)
186
+ end
187
+
188
+ it "ignores dropped columns" do
189
+ updated_table = Table.new(table_name).tap do |t|
190
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
191
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text])
192
+ t.add_column DataColumn.new(:body, Cequel::Type[:text])
193
+ t.add_property TableProperty.build(:comment, "Orig comment")
194
+ end
195
+
196
+ expect(
197
+ described_class.new(orig_table, updated_table).call
198
+ ).to be_empty
199
+ end
200
+
201
+ it "detects new property" do
202
+ updated_table = Table.new(table_name).tap do |t|
203
+ t.add_column PartitionKey.new(:blog_subdomain, Cequel::Type[:text])
204
+ t.add_column ClusteringColumn.new(:slug, Cequel::Type[:text])
205
+ t.add_property TableProperty.build(:comment, "test")
206
+ end
207
+
208
+ expect(
209
+ described_class.new(orig_table, updated_table).call
210
+ ).to set_property(:comment, "test")
211
+ end
212
+ end
213
+
214
+ # Background
215
+
216
+ matcher :set_property do |expected_name, expected_val|
217
+ match do |actual_patch|
218
+ actual_patch.changes
219
+ .any? { |actual_change|
220
+ actual_change.is_a?(Cequel::Schema::Patch::SetTableProperties) &&
221
+ actual_change.properties
222
+ .any?{|p|
223
+ p.name.to_s == expected_name.to_s &&
224
+ expected_val === p.value
225
+ }
226
+ }
227
+ end
228
+ end
229
+
230
+ matcher :drop_index do |index_name|
231
+ match do |actual_patch|
232
+ actual_patch.changes
233
+ .any? { |actual_change|
234
+ actual_change.is_a?(Cequel::Schema::Patch::DropIndex) &&
235
+ actual_change.index_name.to_s == index_name.to_s
236
+ }
237
+ end
238
+ end
239
+
240
+ matcher :add_index do |index_name|
241
+ @column_matcher = ->(_){true}
242
+
243
+ match do |actual_patch|
244
+ actual_patch.changes
245
+ .any? { |actual_change|
246
+ actual_change.is_a?(Cequel::Schema::Patch::AddIndex) &&
247
+ @column_matcher === actual_change.column &&
248
+ actual_change.index_name.to_s == index_name.to_s
249
+ }
250
+ end
251
+
252
+ chain :of_column do |col_name|
253
+ @column_matcher = ->(col) { col.name.to_s == col_name.to_s }
254
+ end
255
+ end
256
+
257
+ matcher :add_column do |name|
258
+ @type_matcher = ->(_){true}
259
+
260
+ match do |actual_patch|
261
+ actual_patch.changes
262
+ .any? { |actual_change|
263
+ actual_change.is_a?(Cequel::Schema::Patch::AddColumn) &&
264
+ actual_change.column.name == name &&
265
+ @type_matcher === actual_change.column.type
266
+ }
267
+ end
268
+
269
+ chain :of_type do |type_or_matcher|
270
+ @type_matcher = if type_or_matcher.respond_to?(:call)
271
+ type_or_matcher
272
+ elsif t = Cequel::Type[type_or_matcher]
273
+ ->(type) { type == t }
274
+ else
275
+ fail "unsupported type matcher: #{type_or_matcher.inspect}"
276
+ end
277
+ end
278
+ end
279
+ end
280
+ end