cassandra_migrations 0.0.1.pre4 → 0.0.1.pre5
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/prepare_for_cassandra +62 -0
- data/lib/cassandra_migrations.rb +1 -0
- data/lib/cassandra_migrations/cassandra.rb +0 -1
- data/lib/cassandra_migrations/cassandra/queries.rb +8 -1
- data/lib/cassandra_migrations/errors.rb +6 -0
- data/lib/cassandra_migrations/migration.rb +89 -0
- data/lib/cassandra_migrations/migration/column_operations.rb +48 -0
- data/lib/cassandra_migrations/migration/table_definition.rb +111 -0
- data/lib/cassandra_migrations/migration/table_operations.rb +46 -0
- data/lib/cassandra_migrations/migrator.rb +4 -4
- data/lib/cassandra_migrations/railtie.rb +6 -0
- data/lib/cassandra_migrations/railtie/generators/cassandra_migration/USAGE +23 -0
- data/lib/cassandra_migrations/railtie/generators/cassandra_migration/cassandra_migration_generator.rb +18 -0
- data/lib/cassandra_migrations/railtie/generators/cassandra_migration/templates/empty_migration.rb.erb +9 -0
- metadata +27 -2
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'colorize'
|
6
|
+
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.banner = "Usage: #{File.basename($0)} [path]"
|
9
|
+
|
10
|
+
opts.on("-h", "--help", "Displays this help info") do
|
11
|
+
puts opts
|
12
|
+
exit 0
|
13
|
+
end
|
14
|
+
|
15
|
+
begin
|
16
|
+
opts.parse!(ARGV)
|
17
|
+
rescue OptionParser::ParseError => e
|
18
|
+
warn e.message
|
19
|
+
puts opts
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if ARGV.empty?
|
25
|
+
abort "Please specify the directory of a rails appilcation, e.g. `#{File.basename($0)} .'"
|
26
|
+
elsif !File.directory?(ARGV.first)
|
27
|
+
abort "`#{ARGV.first}' is not a directory."
|
28
|
+
elsif ARGV.length > 1
|
29
|
+
abort "Too many arguments; please specify only the directory of the rails application."
|
30
|
+
end
|
31
|
+
|
32
|
+
rails_root = ARGV.first
|
33
|
+
|
34
|
+
# create cassandra.yaml
|
35
|
+
if File.exists?(File.expand_path('config/cassandra.yml', rails_root))
|
36
|
+
puts "[skip] 'config/cassandra.yml' already exists".yellow
|
37
|
+
else
|
38
|
+
puts "[new] creating 'config/cassandra.yml' (please update with your own configurations!)".green
|
39
|
+
FileUtils.cp(
|
40
|
+
File.expand_path('../template/cassandra.yml', File.dirname(__FILE__)),
|
41
|
+
File.expand_path('config/cassandra.yml', rails_root)
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
# create db/cassandra_migrations
|
46
|
+
if File.exists?(File.expand_path('db/cassandra_migrate', rails_root))
|
47
|
+
puts "[skip] 'db/cassandra_migrate' already exists".yellow
|
48
|
+
else
|
49
|
+
puts "[new] creating 'db/cassandra_migrate' directory".green
|
50
|
+
FileUtils.mkdir(File.expand_path('db/cassandra_migrate', rails_root))
|
51
|
+
end
|
52
|
+
|
53
|
+
puts '[done] prepared for cassandra!'.green
|
54
|
+
puts ''
|
55
|
+
puts 'Your steps from here are:'.green
|
56
|
+
puts ' 1. configure '.green + 'config/cassandra.yml'.red
|
57
|
+
puts ' 2. run '.green + 'rake cassandra:setup'.red + ' and try starting your application'.green
|
58
|
+
puts ' 3. create your first migration with '.green + 'rails g cassandra_migration'.red
|
59
|
+
puts ' 4. apply your migration with '.green + 'rake cassandra:migrate'.red
|
60
|
+
puts ' 5. run '.green + 'rake cassandra:test:prepare'.red + 'and start testing'.green
|
61
|
+
puts ' 6. have lots of fun!'.green.blink
|
62
|
+
|
data/lib/cassandra_migrations.rb
CHANGED
@@ -10,7 +10,14 @@ module CassandraMigrations
|
|
10
10
|
|
11
11
|
hash.each do |k,v|
|
12
12
|
columns << k.to_s
|
13
|
-
|
13
|
+
|
14
|
+
if v.respond_to?(:strftime)
|
15
|
+
values << "'#{v.strftime('%Y-%m-%d %H:%M:%S%z')}'"
|
16
|
+
elsif v.is_a?(String)
|
17
|
+
values << "'#{v}'"
|
18
|
+
else
|
19
|
+
values << v.to_s
|
20
|
+
end
|
14
21
|
end
|
15
22
|
|
16
23
|
execute("INSERT INTO #{table} (#{columns.join(', ')}) VALUES (#{values.join(', ')})")
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'cassandra_migrations/migration/table_operations'
|
4
|
+
require 'cassandra_migrations/migration/column_operations'
|
5
|
+
|
6
|
+
module CassandraMigrations
|
7
|
+
|
8
|
+
# Base class for all cassandra migration
|
9
|
+
class Migration
|
10
|
+
|
11
|
+
include TableOperations
|
12
|
+
include ColumnOperations
|
13
|
+
|
14
|
+
# Makes +execute+ method directly available to migrations
|
15
|
+
delegate :execute, :to => Cassandra
|
16
|
+
|
17
|
+
# Makes +up+ work if the method in the migration is defined with self.up
|
18
|
+
def up
|
19
|
+
return unless self.class.respond_to?(:up)
|
20
|
+
self.class.instance_to_delegate = self
|
21
|
+
self.class.up
|
22
|
+
end
|
23
|
+
|
24
|
+
# Makes +down+ work if the method in the migration is defined with self.down
|
25
|
+
def down
|
26
|
+
return unless self.class.respond_to?(:down)
|
27
|
+
self.class.instance_to_delegate = self
|
28
|
+
self.class.down
|
29
|
+
end
|
30
|
+
|
31
|
+
# Class variable that holds an instance of Migration when the methods +up+ or
|
32
|
+
# +down+ are called on the class. The class then delegates missing method
|
33
|
+
# calls to this instance.
|
34
|
+
cattr_accessor :instance_to_delegate, :instance_accessor => false
|
35
|
+
|
36
|
+
# Delegate missing method calls to an instance. That's what enables the
|
37
|
+
# writing of migrations using both +def up+ and +def self.up+ sintax.
|
38
|
+
def self.method_missing(name, *args, &block)
|
39
|
+
if instance_to_delegate
|
40
|
+
instance_to_delegate.send(name, *args, &block)
|
41
|
+
else
|
42
|
+
super
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Execute this migration in the named direction.
|
47
|
+
#
|
48
|
+
# The advantage of using this instead of directly calling up or down is that
|
49
|
+
# this method gives informative output and benchmarks the time taken.
|
50
|
+
def migrate(direction)
|
51
|
+
return unless respond_to?(direction)
|
52
|
+
|
53
|
+
case direction
|
54
|
+
when :up then announce_migration "migrating"
|
55
|
+
when :down then announce_migration "reverting"
|
56
|
+
end
|
57
|
+
|
58
|
+
time = Benchmark.measure { send(direction) }
|
59
|
+
|
60
|
+
case direction
|
61
|
+
when :up then announce_migration "migrated (%.4fs)" % time.real; puts
|
62
|
+
when :down then announce_migration "reverted (%.4fs)" % time.real; puts
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# Generates output labeled with name of migration and a line that goes up
|
69
|
+
# to 75 characters long in the terminal
|
70
|
+
def announce_migration(message)
|
71
|
+
text = "#{name}: #{message}"
|
72
|
+
length = [0, 75 - text.length].max
|
73
|
+
puts "== %s %s" % [text, "=" * length]
|
74
|
+
end
|
75
|
+
|
76
|
+
def announce_operation(message)
|
77
|
+
puts " " + message
|
78
|
+
end
|
79
|
+
|
80
|
+
def announce_suboperation(message)
|
81
|
+
puts " -> " + message
|
82
|
+
end
|
83
|
+
|
84
|
+
# Gets the name of the migration
|
85
|
+
def name
|
86
|
+
self.class.name
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'cassandra_migrations/migration/table_definition'
|
4
|
+
|
5
|
+
module CassandraMigrations
|
6
|
+
class Migration
|
7
|
+
|
8
|
+
# Module grouping methods used in migrations to make table operations like:
|
9
|
+
# - adding/removing columns
|
10
|
+
# - changing column types
|
11
|
+
# - renaming columns
|
12
|
+
module ColumnOperations
|
13
|
+
|
14
|
+
# Adds a column to a table.
|
15
|
+
#
|
16
|
+
# options: same options you would pass to create a table with that column
|
17
|
+
# (i.e. :limit might be applicable)
|
18
|
+
|
19
|
+
def add_column(table_name, column_name, type, options = {})
|
20
|
+
table_definition = TableDefinition.new
|
21
|
+
|
22
|
+
if !table_definition.respond_to?(type)
|
23
|
+
raise Errors::MigrationDefinitionError("Type '#{type}' is not valid for cassandra migration.")
|
24
|
+
end
|
25
|
+
|
26
|
+
table_definition.send(type, column_name, options)
|
27
|
+
|
28
|
+
announce_operation "add_column(#{column_name}, #{type})"
|
29
|
+
|
30
|
+
cql = "ALTER TABLE #{table_name} ADD "
|
31
|
+
cql << table_definition.to_add_column_cql
|
32
|
+
announce_suboperation cql
|
33
|
+
|
34
|
+
execute cql
|
35
|
+
end
|
36
|
+
|
37
|
+
# Removes a column from the table
|
38
|
+
def remove_column(table_name, column_name)
|
39
|
+
announce_operation "drop_table(#{table_name})"
|
40
|
+
|
41
|
+
cql = "ALTER TABLE #{table_name} DROP #{column_name}"
|
42
|
+
announce_suboperation cql
|
43
|
+
|
44
|
+
execute cql
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module CassandraMigrations
|
4
|
+
class Migration
|
5
|
+
|
6
|
+
# Used to define a table in a migration of table creation or to
|
7
|
+
# add columns to an existing table.
|
8
|
+
#
|
9
|
+
# An instance of this class is passed to the block of the method
|
10
|
+
# +create_table+, available on every migration.
|
11
|
+
#
|
12
|
+
# This class is also internally used in the method +add_column+.
|
13
|
+
|
14
|
+
class TableDefinition
|
15
|
+
|
16
|
+
def initialize()
|
17
|
+
@columns_name_type_hash = {}
|
18
|
+
@primary_keys = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_create_cql
|
22
|
+
cql = []
|
23
|
+
|
24
|
+
if !@columns_name_type_hash.empty?
|
25
|
+
@columns_name_type_hash.each do |column_name, type|
|
26
|
+
cql << "#{column_name} #{type}"
|
27
|
+
end
|
28
|
+
else
|
29
|
+
raise Errors::MigrationDefinitionError('No columns defined for table.')
|
30
|
+
end
|
31
|
+
|
32
|
+
if !@primary_keys.empty?
|
33
|
+
cql << "PRIMARY KEY(#{@primary_keys.join(', ')})"
|
34
|
+
else
|
35
|
+
raise Errors::MigrationDefinitionError('No primary key defined.')
|
36
|
+
end
|
37
|
+
|
38
|
+
cql.join(', ')
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_add_column_cql
|
42
|
+
cql = ""
|
43
|
+
|
44
|
+
if @columns_name_type_hash.size == 1
|
45
|
+
cql = "#{@columns_name_type_hash.keys.first} #{@columns_name_type_hash.values.first}"
|
46
|
+
elsif @columns_name_type_hash.empty?
|
47
|
+
raise Errors::MigrationDefinitionError('No column to add.')
|
48
|
+
else
|
49
|
+
raise Errors::MigrationDefinitionError('Only one column ca be added at once.')
|
50
|
+
end
|
51
|
+
|
52
|
+
cql
|
53
|
+
end
|
54
|
+
|
55
|
+
def boolean(column_name, options={})
|
56
|
+
@columns_name_type_hash[column_name.to_sym] = :boolean
|
57
|
+
define_primary_keys(column_name) if options[:primary_key]
|
58
|
+
end
|
59
|
+
|
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
|
68
|
+
define_primary_keys(column_name) if options[:primary_key]
|
69
|
+
end
|
70
|
+
|
71
|
+
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
|
79
|
+
define_primary_keys(column_name) if options[:primary_key]
|
80
|
+
end
|
81
|
+
|
82
|
+
def string(column_name, options={})
|
83
|
+
@columns_name_type_hash[column_name.to_sym] = :varchar
|
84
|
+
define_primary_keys(column_name) if options[:primary_key]
|
85
|
+
end
|
86
|
+
|
87
|
+
def text(column_name, options={})
|
88
|
+
@columns_name_type_hash[column_name.to_sym] = :text
|
89
|
+
define_primary_keys(column_name) if options[:primary_key]
|
90
|
+
end
|
91
|
+
|
92
|
+
def datetime(column_name, options={})
|
93
|
+
@columns_name_type_hash[column_name.to_sym] = :timestamp
|
94
|
+
define_primary_keys(column_name) if options[:primary_key]
|
95
|
+
end
|
96
|
+
|
97
|
+
def timestamp(column_name, options={})
|
98
|
+
@columns_name_type_hash[column_name.to_sym] = :timestamp
|
99
|
+
define_primary_keys(column_name) if options[:primary_key]
|
100
|
+
end
|
101
|
+
|
102
|
+
def define_primary_keys(*keys)
|
103
|
+
if !@primary_keys.empty?
|
104
|
+
raise Errors::MigrationDefinitionError('Primary key defined twice for the same table.')
|
105
|
+
end
|
106
|
+
|
107
|
+
@primary_keys = keys.flatten
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'cassandra_migrations/migration/table_definition'
|
4
|
+
|
5
|
+
module CassandraMigrations
|
6
|
+
class Migration
|
7
|
+
|
8
|
+
# Module grouping methods used in migrations to make table operations like:
|
9
|
+
# - creating tables
|
10
|
+
# - dropping tables
|
11
|
+
module TableOperations
|
12
|
+
|
13
|
+
# Creates a new table in the keyspace
|
14
|
+
#
|
15
|
+
# options:
|
16
|
+
# - :primary_keys: single value or array (for compound primary keys). If
|
17
|
+
# not defined, some column must be chosen as primary key in the table definition.
|
18
|
+
|
19
|
+
def create_table(table_name, options = {})
|
20
|
+
table_definition = TableDefinition.new
|
21
|
+
table_definition.define_primary_keys(options[:primary_keys]) if options[:primary_keys]
|
22
|
+
|
23
|
+
yield table_definition if block_given?
|
24
|
+
|
25
|
+
announce_operation "create_table(#{table_name})"
|
26
|
+
|
27
|
+
create_cql = "CREATE TABLE #{table_name} ("
|
28
|
+
create_cql << table_definition.to_create_cql
|
29
|
+
create_cql << ")"
|
30
|
+
|
31
|
+
announce_suboperation create_cql
|
32
|
+
|
33
|
+
execute create_cql
|
34
|
+
end
|
35
|
+
|
36
|
+
# Drops a table
|
37
|
+
def drop_table(table_name)
|
38
|
+
announce_operation "drop_table(#{table_name})"
|
39
|
+
drop_cql = "DROP TABLE #{table_name}"
|
40
|
+
announce_suboperation drop_cql
|
41
|
+
|
42
|
+
execute drop_cql
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -31,7 +31,7 @@ module CassandraMigrations
|
|
31
31
|
if !executed_migrations.empty?
|
32
32
|
count.times do |i|
|
33
33
|
if executed_migrations[i]
|
34
|
-
down(executed_migrations[i], executed_migrations[i])
|
34
|
+
down(executed_migrations[i], executed_migrations[i+1])
|
35
35
|
down_count += 1
|
36
36
|
end
|
37
37
|
end
|
@@ -56,7 +56,7 @@ private
|
|
56
56
|
# load migration
|
57
57
|
require migration_name
|
58
58
|
# run migration
|
59
|
-
get_class_from_migration_name(migration_name).up
|
59
|
+
get_class_from_migration_name(migration_name).new.migrate(:up)
|
60
60
|
|
61
61
|
# update version
|
62
62
|
Cassandra.write!(METADATA_TABLE, {:data_name => 'version', :data_value => get_version_from_migration_name(migration_name).to_s})
|
@@ -66,8 +66,8 @@ private
|
|
66
66
|
# load migration
|
67
67
|
require migration_name
|
68
68
|
# run migration
|
69
|
-
get_class_from_migration_name(migration_name).down
|
70
|
-
|
69
|
+
get_class_from_migration_name(migration_name).new.migrate(:down)
|
70
|
+
|
71
71
|
# downgrade version
|
72
72
|
if previous_migration_name
|
73
73
|
Cassandra.write!(METADATA_TABLE, {:data_name => 'version', :data_value => get_version_from_migration_name(previous_migration_name).to_s})
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Description:
|
2
|
+
Stubs out a new cassandra migration.
|
3
|
+
|
4
|
+
Pass the migration name, either CamelCased or under_scored. A migration
|
5
|
+
class is generated in db/cassandra_migrate, prefixed by a timestamp of the
|
6
|
+
current date and time
|
7
|
+
|
8
|
+
Example:
|
9
|
+
rails generate migration create_tweets
|
10
|
+
|
11
|
+
This will create:
|
12
|
+
db/cassandra_migrate/20080514090912_create_tweets.rb
|
13
|
+
|
14
|
+
Inside this file we'll have a migration ready for completion:
|
15
|
+
class CreateTweets << CassandraMigrations::Migration
|
16
|
+
def up
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def down
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class CassandraMigrationGenerator < Rails::Generators::Base
|
2
|
+
source_root File.expand_path('templates', File.dirname(__FILE__))
|
3
|
+
|
4
|
+
argument :migration_name, :type => :string
|
5
|
+
|
6
|
+
# Interpolates template and creates migration in the application
|
7
|
+
#
|
8
|
+
# Any public method in the generator is run automatically when
|
9
|
+
# the generator is run. To understand fully see
|
10
|
+
# http://asciicasts.com/episodes/218-making-generators-in-rails-3
|
11
|
+
|
12
|
+
def generate_migration
|
13
|
+
file_name = "#{Time.current.utc.strftime('%Y%m%d%H%M%S')}_#{migration_name.underscore}"
|
14
|
+
@migration_class_name = migration_name.camelize
|
15
|
+
|
16
|
+
template "empty_migration.rb.erb", "db/cassandra_migrate/#{file_name}.rb"
|
17
|
+
end
|
18
|
+
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.1.
|
4
|
+
version: 0.0.1.pre5
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -59,6 +59,22 @@ dependencies:
|
|
59
59
|
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '3.2'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: colorize
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0.5'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0.5'
|
62
78
|
- !ruby/object:Gem::Dependency
|
63
79
|
name: rspec
|
64
80
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,22 +110,31 @@ dependencies:
|
|
94
110
|
description: A gem to manage Cassandra database schema for Rails. This gem offers
|
95
111
|
migrations and environment specific databases out-of-the-box for Rails users.
|
96
112
|
email: guberthenrique@hotmail.com
|
97
|
-
executables:
|
113
|
+
executables:
|
114
|
+
- prepare_for_cassandra
|
98
115
|
extensions: []
|
99
116
|
extra_rdoc_files: []
|
100
117
|
files:
|
101
118
|
- lib/cassandra_migrations.rb
|
119
|
+
- lib/cassandra_migrations/migration.rb
|
102
120
|
- lib/cassandra_migrations/migrator.rb
|
103
121
|
- lib/cassandra_migrations/cassandra.rb
|
104
122
|
- lib/cassandra_migrations/railtie.rb
|
105
123
|
- lib/cassandra_migrations/cassandra/keyspace_operations.rb
|
106
124
|
- lib/cassandra_migrations/cassandra/queries.rb
|
107
125
|
- lib/cassandra_migrations/config.rb
|
126
|
+
- lib/cassandra_migrations/migration/table_operations.rb
|
127
|
+
- lib/cassandra_migrations/migration/column_operations.rb
|
128
|
+
- lib/cassandra_migrations/migration/table_definition.rb
|
108
129
|
- lib/cassandra_migrations/railtie/initializer.rb
|
130
|
+
- lib/cassandra_migrations/railtie/generators/cassandra_migration/cassandra_migration_generator.rb
|
131
|
+
- lib/cassandra_migrations/railtie/generators/cassandra_migration/templates/empty_migration.rb.erb
|
132
|
+
- lib/cassandra_migrations/railtie/generators/cassandra_migration/USAGE
|
109
133
|
- lib/cassandra_migrations/railtie/tasks.rake
|
110
134
|
- lib/cassandra_migrations/errors.rb
|
111
135
|
- spec/cassandra_migrations_spec.rb
|
112
136
|
- spec/cassandra_migrations/cassandra_spec.rb
|
137
|
+
- bin/prepare_for_cassandra
|
113
138
|
homepage: https://github.com/hsgubert/cassandra_migrations
|
114
139
|
licenses:
|
115
140
|
- MIT
|