cequel 2.1.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +2 -2
- data/README.md +8 -0
- data/lib/cequel/errors.rb +2 -0
- data/lib/cequel/metal/new_relic_instrumentation.rb +2 -1
- data/lib/cequel/record.rb +8 -0
- data/lib/cequel/record/schema.rb +30 -23
- data/lib/cequel/schema.rb +3 -2
- data/lib/cequel/schema/column.rb +11 -1
- data/lib/cequel/schema/keyspace.rb +18 -7
- data/lib/cequel/schema/patch.rb +152 -0
- data/lib/cequel/schema/table.rb +55 -137
- data/lib/cequel/schema/table_desc_dsl.rb +196 -0
- data/lib/cequel/schema/table_differ.rb +112 -0
- data/lib/cequel/schema/table_property.rb +14 -0
- data/lib/cequel/schema/table_reader.rb +81 -85
- data/lib/cequel/schema/table_updater.rb +0 -17
- data/lib/cequel/schema/table_writer.rb +10 -9
- data/lib/cequel/version.rb +1 -1
- data/spec/examples/metal/data_set_spec.rb +156 -153
- data/spec/examples/metal/keyspace_spec.rb +4 -4
- data/spec/examples/record/associations_spec.rb +6 -0
- data/spec/examples/record/mass_assignment_spec.rb +2 -2
- data/spec/examples/record/properties_spec.rb +1 -0
- data/spec/examples/record/record_set_spec.rb +1 -1
- data/spec/examples/schema/patch_spec.rb +190 -0
- data/spec/examples/schema/table_differ_spec.rb +280 -0
- data/spec/examples/schema/table_reader_spec.rb +379 -354
- data/spec/examples/schema/table_updater_spec.rb +0 -12
- data/spec/examples/spec_helper.rb +5 -5
- data/spec/examples/spec_support/preparation_spec.rb +4 -0
- data/spec/support/helpers.rb +23 -0
- metadata +9 -6
- data/lib/cequel/schema/create_table_dsl.rb +0 -88
- data/lib/cequel/schema/table_synchronizer.rb +0 -180
- 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",
|
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
|
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",
|
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
|
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', :
|
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', :
|
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
|
@@ -806,7 +806,7 @@ describe Cequel::Record::RecordSet do
|
|
806
806
|
end
|
807
807
|
end
|
808
808
|
|
809
|
-
context 'allow_filtering!',
|
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
|