cassandra_migrations 0.0.4 → 0.0.5

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.
@@ -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: