cassandra_migrations 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,7 +10,7 @@ module CassandraMigrations
10
10
 
11
11
  value_hash.each do |column, value|
12
12
  columns << column.to_s
13
- values << to_cql_value(value)
13
+ values << to_cql_value(column, value, table, options)
14
14
  end
15
15
 
16
16
  query = "INSERT INTO #{table} (#{columns.join(', ')}) VALUES (#{values.join(', ')})"
@@ -25,7 +25,7 @@ module CassandraMigrations
25
25
  def update!(table, selection, value_hash, options={})
26
26
  set_terms = []
27
27
  value_hash.each do |column, value|
28
- set_terms << "#{column} = #{to_cql_value(value)}"
28
+ set_terms << "#{column} = #{to_cql_value(column, value, table, options)}"
29
29
  end
30
30
 
31
31
  query = "UPDATE #{table}"
@@ -53,6 +53,10 @@ module CassandraMigrations
53
53
  if options[:limit]
54
54
  query_string << " LIMIT #{options[:limit]}"
55
55
  end
56
+
57
+ if options[:allow_filtering]
58
+ query_string << " ALLOW FILTERING"
59
+ end
56
60
 
57
61
  execute(query_string)
58
62
  end
@@ -68,13 +72,49 @@ module CassandraMigrations
68
72
 
69
73
  private
70
74
 
71
- def to_cql_value(value)
75
+ def get_column_type(table, column)
76
+ column_info = client.execute("SELECT VALIDATOR FROM system.schema_columns WHERE keyspace_name = '#{client.keyspace}' AND columnfamily_name = '#{table}' AND column_name = '#{column}'")
77
+ raw_type = column_info.first['validator']
78
+
79
+ case
80
+ when raw_type.include?('SetType'); :set
81
+ when raw_type.include?('ListType'); :list
82
+ when raw_type.include?('MapType'); :map
83
+ when raw_type.include?('BooleanType'); :boolean
84
+ when raw_type.include?('FloatType'); :float
85
+ when raw_type.include?('Int32Type'); :int
86
+ when raw_type.include?('DateType'); :timestamp
87
+ when raw_type.include?('UTF8Type'); :string
88
+ when raw_type.include?('BytesType'); :blob
89
+ when raw_type.include?('UUIDType'); :uuid
90
+ when raw_type.include?('DoubleType'); :double
91
+ when raw_type.include?('InetAddressType'); :inet
92
+ when raw_type.include?('AsciiType'); :ascii
93
+ when raw_type.include?('LongType'); :bigint
94
+ when raw_type.include?('DecimalType'); :decimal
95
+ when raw_type.include?('TimeUUIDType'); :timeuuid
96
+ end
97
+ end
98
+
99
+ def to_cql_value(column, value, table, options={})
100
+ operator = options[:operations] ? options[:operations][column.to_sym] : nil
101
+ operation = operator ? "#{column} #{operator} " : ''
102
+
72
103
  if value.respond_to?(:strftime)
73
104
  "'#{value.strftime('%Y-%m-%d %H:%M:%S%z')}'"
74
105
  elsif value.is_a?(String)
75
- "'#{value}'"
76
- elsif value.is_a?(Hash)
77
- "{ #{value.reduce([]) {|sum, (key, value)| sum << "'#{key}': '#{value}'" }.join(", ") } }"
106
+ "'#{value}'"
107
+ elsif value.is_a?(Array)
108
+ type = get_column_type(table, column)
109
+ values = %[#{value.map {|v| "'#{v}'"} * ', '}]
110
+
111
+ if type && type == :list
112
+ %[#{operation}[#{values}]]
113
+ else # it must be a set!
114
+ %[#{operation}{#{values}}]
115
+ end
116
+ elsif value.is_a?(Hash)
117
+ "#{operation}{ #{value.reduce([]) {|sum, (key, value)| sum << "'#{key}': '#{value}'" }.join(", ") } }"
78
118
  else
79
119
  value.to_s
80
120
  end
@@ -26,13 +26,13 @@ module CassandraMigrations
26
26
  cql << "#{column_name} #{type}"
27
27
  end
28
28
  else
29
- raise Errors::MigrationDefinitionError('No columns defined for table.')
29
+ raise Errors::MigrationDefinitionError, 'No columns defined for table.'
30
30
  end
31
31
 
32
32
  if !@primary_keys.empty?
33
33
  cql << "PRIMARY KEY(#{@primary_keys.join(', ')})"
34
34
  else
35
- raise Errors::MigrationDefinitionError('No primary key defined.')
35
+ raise Errors::MigrationDefinitionError, 'No primary key defined.'
36
36
  end
37
37
 
38
38
  cql.join(', ')
@@ -44,78 +44,138 @@ module CassandraMigrations
44
44
  if @columns_name_type_hash.size == 1
45
45
  cql = "#{@columns_name_type_hash.keys.first} #{@columns_name_type_hash.values.first}"
46
46
  elsif @columns_name_type_hash.empty?
47
- raise Errors::MigrationDefinitionError('No column to add.')
47
+ raise Errors::MigrationDefinitionError, 'No column to add.'
48
48
  else
49
- raise Errors::MigrationDefinitionError('Only one column can be added at once.')
49
+ raise Errors::MigrationDefinitionError, 'Only one column can be added at once.'
50
50
  end
51
51
 
52
52
  cql
53
53
  end
54
54
 
55
55
  def boolean(column_name, options={})
56
- @columns_name_type_hash[column_name.to_sym] = :boolean
56
+ @columns_name_type_hash[column_name.to_sym] = column_type_for(:boolean, options)
57
57
  define_primary_keys(column_name) if options[:primary_key]
58
58
  end
59
59
 
60
60
  def integer(column_name, options={})
61
- if options[:limit].nil? || options[:limit] == 4
62
- @columns_name_type_hash[column_name.to_sym] = :int
63
- elsif options[:limit] == 8
64
- @columns_name_type_hash[column_name.to_sym] = :bigint
65
- else
66
- raise Errors::MigrationDefinitionError(':limit option should be 4 or 8 for integers.')
67
- end
61
+ @columns_name_type_hash[column_name.to_sym] = column_type_for(:integer, options)
68
62
  define_primary_keys(column_name) if options[:primary_key]
69
63
  end
70
64
 
71
65
  def float(column_name, options={})
72
- if options[:limit].nil? || options[:limit] == 4
73
- @columns_name_type_hash[column_name.to_sym] = :float
74
- elsif options[:limit] == 8
75
- @columns_name_type_hash[column_name.to_sym] = :double
76
- else
77
- raise Errors::MigrationDefinitionError(':limit option should be 4 or 8 for floats.')
78
- end
66
+ @columns_name_type_hash[column_name.to_sym] = column_type_for(:float, options)
79
67
  define_primary_keys(column_name) if options[:primary_key]
80
68
  end
81
69
 
82
70
  def string(column_name, options={})
83
- @columns_name_type_hash[column_name.to_sym] = :varchar
71
+ @columns_name_type_hash[column_name.to_sym] = column_type_for(:string, options)
84
72
  define_primary_keys(column_name) if options[:primary_key]
85
73
  end
86
74
 
87
75
  def text(column_name, options={})
88
- @columns_name_type_hash[column_name.to_sym] = :text
76
+ @columns_name_type_hash[column_name.to_sym] = column_type_for(:text, options)
89
77
  define_primary_keys(column_name) if options[:primary_key]
90
78
  end
91
79
 
92
80
  def datetime(column_name, options={})
93
- @columns_name_type_hash[column_name.to_sym] = :timestamp
81
+ @columns_name_type_hash[column_name.to_sym] = column_type_for(:datetime, options)
94
82
  define_primary_keys(column_name) if options[:primary_key]
95
83
  end
96
84
 
97
85
  def timestamp(column_name, options={})
98
- @columns_name_type_hash[column_name.to_sym] = :timestamp
86
+ @columns_name_type_hash[column_name.to_sym] = column_type_for(:timestamp, options)
99
87
  define_primary_keys(column_name) if options[:primary_key]
100
88
  end
101
89
 
102
90
  def uuid(column_name, options={})
103
- @columns_name_type_hash[column_name.to_sym] = :uuid
91
+ @columns_name_type_hash[column_name.to_sym] = column_type_for(:uuid, options)
104
92
  define_primary_keys(column_name) if options[:primary_key]
105
93
  end
106
94
 
107
95
  def timeuuid(column_name, options={})
108
- @columns_name_type_hash[column_name.to_sym] = :timeuuid
96
+ @columns_name_type_hash[column_name.to_sym] = column_type_for(:timeuuid, options)
109
97
  define_primary_keys(column_name) if options[:primary_key]
110
98
  end
111
99
 
100
+ def list(column_name, options={})
101
+ type = options[:type]
102
+ if type.nil?
103
+ raise Errors::MigrationDefinitionError, 'A list must define a collection type.'
104
+ elsif !self.respond_to?(type)
105
+ raise Errors::MigrationDefinitionError, "Type '#{type}' is not valid for cassandra migration."
106
+ end
107
+ if options[:primary_key]
108
+ raise Errors::MigrationDefinitionError, 'A collection cannot be used as a primary key.'
109
+ end
110
+ @columns_name_type_hash[column_name.to_sym] = :"list<#{column_type_for(type)}>"
111
+ end
112
+
113
+ def set(column_name, options={})
114
+ type = options[:type]
115
+ if type.nil?
116
+ raise Errors::MigrationDefinitionError, 'A set must define a collection type.'
117
+ elsif !self.respond_to?(type)
118
+ raise Errors::MigrationDefinitionError, "Type '#{type}' is not valid for cassandra migration."
119
+ end
120
+ if options[:primary_key]
121
+ raise Errors::MigrationDefinitionError, 'A collection cannot be used as a primary key.'
122
+ end
123
+ @columns_name_type_hash[column_name.to_sym] = :"set<#{column_type_for(type)}>"
124
+ end
125
+
126
+ def map(column_name, options={})
127
+ key_type, value_type = options[:key_type], options[:value_type]
128
+ [key_type, value_type].each_with_index do |type, index|
129
+ if type.nil?
130
+ raise Errors::MigrationDefinitionError, "A map must define a #{index = 0 ? 'key' : 'value'} type."
131
+ elsif !self.respond_to?(type)
132
+ raise Errors::MigrationDefinitionError, "Type '#{type}' is not valid for cassandra migration."
133
+ end
134
+ end
135
+
136
+ if options[:primary_key]
137
+ raise Errors::MigrationDefinitionError, 'A collection cannot be used as a primary key.'
138
+ end
139
+ @columns_name_type_hash[column_name.to_sym] = :"map<#{column_type_for(key_type)},#{column_type_for(value_type)}>"
140
+ end
141
+
112
142
  def define_primary_keys(*keys)
113
143
  if !@primary_keys.empty?
114
- raise Errors::MigrationDefinitionError('Primary key defined twice for the same table.')
144
+ raise Errors::MigrationDefinitionError, 'Primary key defined twice for the same table.'
115
145
  end
116
146
 
117
147
  @primary_keys = keys.flatten
118
148
  end
149
+
150
+ private
151
+
152
+ def column_type_for(ruby_type, options={})
153
+ limit = options[:limit]
154
+ case ruby_type
155
+ when :boolean, :text, :timestamp, :uuid, :timeuuid
156
+ ruby_type
157
+ when :integer
158
+ if limit.nil? || limit == 4
159
+ :int
160
+ elsif limit == 8
161
+ :bigint
162
+ else
163
+ raise Errors::MigrationDefinitionError, ':limit option should be 4 or 8 for integers.'
164
+ end
165
+ when :float
166
+ if limit.nil? || limit == 4
167
+ :float
168
+ elsif limit == 8
169
+ :double
170
+ else
171
+ raise Errors::MigrationDefinitionError, ':limit option should be 4 or 8 for floats.'
172
+ end
173
+ when :string
174
+ :varchar
175
+ when :datetime
176
+ :timestamp
177
+ end
178
+ end
119
179
  end
120
180
  end
121
181
  end
@@ -33,6 +33,14 @@ module CassandraMigrations
33
33
  execute create_cql
34
34
  end
35
35
 
36
+ def create_index(table_name, column_name, options = {})
37
+ announce_operation "create_index(#{table_name})"
38
+ create_index_cql = "CREATE INDEX #{options[:name]} ON #{table_name} (#{column_name})".squeeze(' ')
39
+ announce_suboperation create_index_cql
40
+
41
+ execute create_index_cql
42
+ end
43
+
36
44
  # Drops a table
37
45
  def drop_table(table_name)
38
46
  announce_operation "drop_table(#{table_name})"
@@ -41,6 +49,19 @@ module CassandraMigrations
41
49
 
42
50
  execute drop_cql
43
51
  end
52
+
53
+ def drop_index(table_or_index_name, column_name = nil, options = {})
54
+ if column_name
55
+ index_name = "#{table_or_index_name}_#{column_name}_idx"
56
+ else
57
+ index_name = table_or_index_name
58
+ end
59
+ drop_index_cql = "DROP INDEX #{options[:if_exists] ? 'IF EXISTS' : ''}#{index_name}"
60
+ announce_suboperation drop_index_cql
61
+
62
+ execute drop_index_cql
63
+ end
64
+
44
65
  end
45
66
  end
46
67
  end
@@ -5,6 +5,16 @@ describe CassandraMigrations::Cassandra::Queries do
5
5
 
6
6
  class TestQueryExecutor
7
7
  extend CassandraMigrations::Cassandra::Queries
8
+
9
+ def self.column_type=(column_type)
10
+ @column_type = column_type
11
+ end
12
+
13
+ private
14
+
15
+ def self.get_column_type(table, column)
16
+ @column_type
17
+ end
8
18
  end
9
19
 
10
20
  describe '.write!' do
@@ -28,6 +38,39 @@ describe CassandraMigrations::Cassandra::Queries do
28
38
 
29
39
  TestQueryExecutor.write!('people', {:name => 'John'}, :ttl => 3600)
30
40
  end
41
+
42
+ context 'when dealing with collections' do
43
+
44
+ it 'should handle setting a set collection column value' do
45
+ TestQueryExecutor.column_type = :set
46
+
47
+ TestQueryExecutor.should_receive(:execute).with(
48
+ "INSERT INTO people (friends) VALUES ({'John', 'Ringo', 'Paul', 'George'})"
49
+ )
50
+
51
+ TestQueryExecutor.write!('people', {friends: ['John', 'Ringo', 'Paul', 'George']})
52
+ end
53
+
54
+ it 'should handle setting a list collection column value' do
55
+ TestQueryExecutor.column_type = :list
56
+
57
+ TestQueryExecutor.should_receive(:execute).with(
58
+ "INSERT INTO people (friends) VALUES (['John', 'Ringo', 'Paul', 'George'])"
59
+ )
60
+
61
+ TestQueryExecutor.write!('people', {friends: ['John', 'Ringo', 'Paul', 'George']})
62
+ end
63
+
64
+ it 'should handle setting a map collection column value' do
65
+ TestQueryExecutor.column_type = :map
66
+
67
+ TestQueryExecutor.should_receive(:execute).with(
68
+ "INSERT INTO people (friends) VALUES ({ 'talent': 'John', 'drums': 'Ringo', 'voice': 'Paul', 'rhythm': 'George' })"
69
+ )
70
+
71
+ TestQueryExecutor.write!('people', {friends: {talent: 'John', drums: 'Ringo', voice: 'Paul', rhythm: 'George'}})
72
+ end
73
+ end
31
74
  end
32
75
 
33
76
  describe '.update!' do
@@ -49,6 +92,109 @@ describe CassandraMigrations::Cassandra::Queries do
49
92
 
50
93
  TestQueryExecutor.update!('people', "name = 'John'", {:name => 'Johnny'}, :ttl => 3600)
51
94
  end
95
+
96
+ context 'when dealing with collections' do
97
+
98
+ it 'should handle setting a set collection column' do
99
+ TestQueryExecutor.column_type = :set
100
+
101
+ TestQueryExecutor.should_receive(:execute).with(
102
+ "UPDATE people SET friends = {'John', 'Ringo', 'Paul', 'George'} WHERE name = 'Stuart'"
103
+ )
104
+
105
+ TestQueryExecutor.update!('people', "name = 'Stuart'", {friends: ['John', 'Ringo', 'Paul', 'George']})
106
+ end
107
+
108
+ it 'should handle adding elements to a set collection column' do
109
+ TestQueryExecutor.column_type = :set
110
+
111
+ TestQueryExecutor.should_receive(:execute).with(
112
+ "UPDATE people SET friends = friends + {'John', 'Ringo', 'Paul', 'George'} WHERE name = 'Stuart'"
113
+ )
114
+
115
+ TestQueryExecutor.update!('people', "name = 'Stuart'",
116
+ {friends: ['John', 'Ringo', 'Paul', 'George']},
117
+ {operations: {friends: :+}})
118
+ end
119
+
120
+ it 'should handle removing elements from a set collection column' do
121
+ TestQueryExecutor.column_type = :set
122
+
123
+ TestQueryExecutor.should_receive(:execute).with(
124
+ "UPDATE people SET friends = friends - {'John', 'Ringo', 'Paul', 'George'} WHERE name = 'Stuart'"
125
+ )
126
+
127
+ TestQueryExecutor.update!('people', "name = 'Stuart'",
128
+ {friends: ['John', 'Ringo', 'Paul', 'George']},
129
+ {operations: {friends: :-}})
130
+ end
131
+
132
+ it 'should handle setting a list collection column' do
133
+ TestQueryExecutor.column_type = :list
134
+
135
+ TestQueryExecutor.should_receive(:execute).with(
136
+ "UPDATE people SET friends = ['John', 'Ringo', 'Paul', 'George'] WHERE name = 'Stuart'"
137
+ )
138
+
139
+ TestQueryExecutor.update!('people', "name = 'Stuart'", {friends: ['John', 'Ringo', 'Paul', 'George']})
140
+ end
141
+
142
+ it 'should handle adding elements to a list collection column' do
143
+ TestQueryExecutor.column_type = :list
144
+
145
+ TestQueryExecutor.should_receive(:execute).with(
146
+ "UPDATE people SET friends = friends + ['John', 'Ringo', 'Paul', 'George'] WHERE name = 'Stuart'"
147
+ )
148
+
149
+ TestQueryExecutor.update!('people', "name = 'Stuart'",
150
+ {friends: ['John', 'Ringo', 'Paul', 'George']},
151
+ {operations: {friends: :+}})
152
+ end
153
+
154
+ it 'should handle removing elements from a list collection column' do
155
+ TestQueryExecutor.column_type = :list
156
+
157
+ TestQueryExecutor.should_receive(:execute).with(
158
+ "UPDATE people SET friends = friends - ['John', 'Ringo', 'Paul', 'George'] WHERE name = 'Stuart'"
159
+ )
160
+
161
+ TestQueryExecutor.update!('people', "name = 'Stuart'",
162
+ {friends: ['John', 'Ringo', 'Paul', 'George']},
163
+ {operations: {friends: :-}})
164
+ end
165
+
166
+ it 'should handle setting a map collection column' do
167
+ TestQueryExecutor.column_type = :map
168
+
169
+ TestQueryExecutor.should_receive(:execute).with(
170
+ "UPDATE people SET friends = { 'talent': 'John', 'drums': 'Ringo', 'voice': 'Paul', 'rhythm': 'George' } WHERE name = 'Stuart'"
171
+ )
172
+
173
+ TestQueryExecutor.update!('people', "name = 'Stuart'", {friends: {talent: 'John', drums: 'Ringo', voice: 'Paul', rhythm: 'George'}})
174
+ end
175
+
176
+ it 'should handle adding elements to a map collection column' do
177
+ TestQueryExecutor.column_type = :map
178
+
179
+ TestQueryExecutor.should_receive(:execute).with(
180
+ "UPDATE people SET friends = friends + { 'talent': 'John', 'drums': 'Ringo', 'voice': 'Paul', 'rhythm': 'George' } WHERE name = 'Stuart'"
181
+ )
182
+
183
+ TestQueryExecutor.update!('people', "name = 'Stuart'",
184
+ {friends: {talent: 'John', drums: 'Ringo', voice: 'Paul', rhythm: 'George'}},
185
+ {operations: {friends: :+}})
186
+ end
187
+
188
+ it 'should handle removing elements from a map collection column' do
189
+ TestQueryExecutor.column_type = :map
190
+
191
+ TestQueryExecutor.should_receive(:execute).with(
192
+ "DELETE friends['drums'] FROM people WHERE name = 'Stuart'"
193
+ )
194
+
195
+ TestQueryExecutor.delete!('people', "name = 'Stuart'", :projection => "friends['drums']")
196
+ end
197
+ end
52
198
  end
53
199
 
54
200
  describe '.select' do
@@ -1,7 +1,26 @@
1
1
  # encoding : utf-8
2
2
  require 'spec_helper'
3
3
 
4
+ module CassandraMigrations
5
+
6
+ # Temporarily monkey path Migration to allow for testing generated CQL
7
+ # and suppress announcements
8
+ class Migration
9
+ attr_reader :cql
10
+
11
+ def execute(cql)
12
+ @cql = cql
13
+ end
14
+
15
+ private
16
+ def announce_migration(message); end
17
+ def announce_operation(message); end
18
+ def announce_suboperation(message); end
19
+ end
20
+ end
21
+
4
22
  describe CassandraMigrations do
23
+
5
24
  it "should define modules" do
6
25
  defined?(CassandraMigrations).should be_true
7
26
  defined?(CassandraMigrations::Railtie).should be_true
@@ -11,4 +30,139 @@ describe CassandraMigrations do
11
30
  defined?(CassandraMigrations::Migrator).should be_true
12
31
  defined?(CassandraMigrations::Config).should be_true
13
32
  end
33
+
34
+ context 'a migration' do
35
+ before do
36
+ require_relative 'fixtures/migrations/migrations'
37
+ end
38
+
39
+ context 'without a primary key' do
40
+ before do
41
+ @migration = WithoutAPrimaryKey.new
42
+ end
43
+
44
+ it 'should be invalid' do
45
+ expect { @migration.up }.to raise_error(CassandraMigrations::Errors::MigrationDefinitionError, /No primary key defined./)
46
+ end
47
+ end
48
+
49
+ context 'that is valid' do
50
+ before do
51
+ @migration = CreateKitchenSink.new
52
+ end
53
+
54
+ it 'should have a name' do
55
+ expect(@migration.send(:name)).to eq('CreateKitchenSink')
56
+ end
57
+
58
+ it 'should produce a valid CQL create statement' do
59
+ @migration.up
60
+ expected_cql = "CREATE TABLE kitchen_sink (id uuid, a_string varchar, a_timestamp timestamp, a_float float, a_list_of_strings list<varchar>, PRIMARY KEY(id))"
61
+ expect(@migration.cql).to eq(expected_cql)
62
+ end
63
+ end
64
+
65
+ context 'with a list collection column declaration' do
66
+ before do
67
+ @migration = CollectionsListMigration.new
68
+ end
69
+
70
+ it 'should produce a valid CQL create statement' do
71
+ @migration.up
72
+ expected_cql = "CREATE TABLE collection_lists (id uuid, list_1 list<varchar>, PRIMARY KEY(id))"
73
+ expect(@migration.cql).to eq(expected_cql)
74
+ end
75
+
76
+ context 'using invalid types' do
77
+ before do
78
+ @migration = BadCollectionsListMigration.new
79
+ end
80
+
81
+ it 'should be invalid' do
82
+ expect { @migration.up }.to raise_error(CassandraMigrations::Errors::MigrationDefinitionError, /Type 'chupacabra' is not valid for cassandra migration./)
83
+ end
84
+ end
85
+ end
86
+
87
+ context 'with a set collection column declaration' do
88
+ before do
89
+ @migration = CollectionsSetMigration.new
90
+ end
91
+
92
+ it 'should produce a valid CQL create statement' do
93
+ @migration.up
94
+ expected_cql = "CREATE TABLE collection_lists (id uuid, set_2 set<float>, PRIMARY KEY(id))"
95
+ expect(@migration.cql).to eq(expected_cql)
96
+ end
97
+
98
+ context 'using invalid types' do
99
+ before do
100
+ @migration = BadCollectionsSetMigration.new
101
+ end
102
+
103
+ it 'should be invalid' do
104
+ expect { @migration.up }.to raise_error(CassandraMigrations::Errors::MigrationDefinitionError, /Type 'narwhal' is not valid for cassandra migration./)
105
+ end
106
+ end
107
+ end
108
+
109
+ context 'with a map collection column declaration' do
110
+ before do
111
+ @migration = CollectionsMapMigration.new
112
+ end
113
+
114
+ it 'should produce a valid CQL create statement' do
115
+ @migration.up
116
+ expected_cql = "CREATE TABLE collection_lists (id uuid, map_1 map<varchar,float>, PRIMARY KEY(id))"
117
+ expect(@migration.cql).to eq(expected_cql)
118
+ end
119
+
120
+ context 'using invalid types' do
121
+ before do
122
+ @migration = BadCollectionsMapMigration.new
123
+ end
124
+
125
+ it 'should be invalid' do
126
+ expect { @migration.up }.to raise_error(CassandraMigrations::Errors::MigrationDefinitionError, /Type 'unicorns' is not valid for cassandra migration./)
127
+ end
128
+ end
129
+ end
130
+
131
+ context 'with an secondary index definition' do
132
+ before do
133
+ @migration = MigrationWithSecondaryIndex.new
134
+ end
135
+
136
+ it 'should produce a valid CQL create statement' do
137
+ @migration.up
138
+ expected_cql = "CREATE INDEX ON with_indexes (a_string)"
139
+ expect(@migration.cql).to eq(expected_cql)
140
+ end
141
+
142
+ it 'should produce a valid CQL drop statement' do
143
+ @migration.down
144
+ expected_cql = "DROP INDEX with_indexes_a_string_idx"
145
+ expect(@migration.cql).to eq(expected_cql)
146
+ end
147
+ end
148
+
149
+ context 'with a named secondary index definition' do
150
+ before do
151
+ @migration = MigrationWithANamedSecondaryIndex.new
152
+ end
153
+
154
+ it 'should produce a valid CQL create statement' do
155
+ @migration.up
156
+ expected_cql = "CREATE INDEX by_another_string ON with_indexes (another_string)"
157
+ expect(@migration.cql).to eq(expected_cql)
158
+ end
159
+
160
+ it 'should produce a valid CQL drop statement' do
161
+ @migration.down
162
+ expected_cql = "DROP INDEX by_another_string"
163
+ expect(@migration.cql).to eq(expected_cql)
164
+ end
165
+ end
166
+
167
+ end
14
168
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cassandra_migrations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: