lib/cassandra/mapper/extend/migrate.rb
class Cassandra::Mapper
MigrateError = Class.new StandardError
class << self
def force_migrate
auto_migrate_keyspaces
instances.each(&:force_migrate)
@force_migrate_cf = true
end
def auto_migrate
auto_migrate_keyspaces
instances.each(&:auto_migrate)
@auto_migrate_cf = true
end
def new(*)
super.tap do |it|
it.auto_migrate if @auto_migrate_cf
it.force_migrate if @force_migrate_cf
end
end
def auto_migrate_keyspaces
system = Cassandra.new('system', server)
keyspaces = system.send(:client).describe_keyspaces
keyspaces_schema.each do |keyspace|
found = keyspaces.find {|it| it.name == keyspace.name }
if found
unless schema_match? found, keyspace
raise MigrateError, "#{keyspace.name} exists and not matches schema"
end
else
system.add_keyspace keyspace
end
end
end
def keyspaces_schema
schema[:keyspaces].map do |name|
options = schema.fetch(env, {}).fetch(name, {})
options = Utility::Hash.stringify_keys options
strategy = options.delete('strategy') || 'SimpleStrategy'
durable = options.delete('durable_writes') != false && name != :test
options['replication_factor'] = options.fetch('replication_factor', 1).to_s
Cassandra::Keyspace.new \
name: "#{name}_#{env}",
strategy_class: strategy,
strategy_options: options,
durable_writes: durable,
cf_defs: []
end
end
def schema_match?(actual, blueprint)
actual.strategy_class.include?(blueprint.strategy_class) and
actual.strategy_options == blueprint.strategy_options
end
end
def force_migrate
migrate do
keyspace.drop_column_family cf_schema.name
keyspace.add_column_family cf_schema
end
end
def auto_migrate
migrate do |actual, blueprint|
raise MigrateError, <<-ERROR
#{actual.name} exists and not matches comparator.
actual: #{actual.comparator_type}
expected: #{blueprint.comparator_type}
ERROR
end
end
def migrate
blueprint = cf_schema
actual = keyspace.column_families[blueprint.name]
if actual
comparator = actual.comparator_type.gsub('org.apache.cassandra.db.marshal.', '')
yield actual, blueprint unless comparator == blueprint.comparator_type
else
keyspace.add_column_family blueprint
end
end
def cf_schema
subkey_types = config.subkey.map do |it|
Convert.type config.type(it)
end
# field subkey
subkey_types.push Convert::TEXT_TYPE
Cassandra::ColumnFamily.new \
keyspace: keyspace.keyspace,
name: table,
comparator_type: "CompositeType(#{subkey_types.join ','})"
end
end